Merge inbound to m-c. a=merge

This commit is contained in:
Ryan VanderMeulen 2015-02-11 16:21:36 -05:00
commit 1dcbd6bfde
329 changed files with 11533 additions and 8484 deletions

View File

@ -1158,7 +1158,7 @@ ifdef XPT_NAME #{
ifndef NO_DIST_INSTALL
ifndef NO_INTERFACES_MANIFEST
misc:: $(call mkdir_deps,$(FINAL_TARGET)/components)
export:: $(call mkdir_deps,$(FINAL_TARGET)/components)
$(call py_action,buildlist,$(FINAL_TARGET)/components/interfaces.manifest 'interfaces $(XPT_NAME)')
$(call py_action,buildlist,$(FINAL_TARGET)/chrome.manifest 'manifest components/interfaces.manifest')
endif

View File

@ -71,7 +71,6 @@ EXPORTS += [
'nsDOMJSUtils.h',
'nsDOMNavigationTiming.h',
'nsDOMString.h',
'nsElementFrameLoaderOwner.h',
'nsFocusManager.h',
'nsFrameMessageManager.h',
'nsGenericDOMDataNode.h',
@ -260,7 +259,6 @@ UNIFIED_SOURCES += [
'nsDOMSettableTokenList.cpp',
'nsDOMTokenList.cpp',
'nsDOMWindowList.cpp',
'nsElementFrameLoaderOwner.cpp',
'nsFocusManager.cpp',
'nsFormData.cpp',
'nsFrameLoader.cpp',

View File

@ -379,13 +379,11 @@ public:
nsRefPtr<EventListenerManager> mListenerManager;
};
static bool
EventListenerManagerHashInitEntry(PLDHashTable *table, PLDHashEntryHdr *entry,
const void *key)
static void
EventListenerManagerHashInitEntry(PLDHashEntryHdr *entry, const void *key)
{
// Initialize the entry with placement new
new (entry) EventListenerManagerMapEntry(key);
return true;
}
static void

View File

@ -3957,8 +3957,8 @@ SubDocClearEntry(PLDHashTable *table, PLDHashEntryHdr *entry)
}
}
static bool
SubDocInitEntry(PLDHashTable *table, PLDHashEntryHdr *entry, const void *key)
static void
SubDocInitEntry(PLDHashEntryHdr *entry, const void *key)
{
SubDocMapEntry *e =
const_cast<SubDocMapEntry *>
@ -3968,7 +3968,6 @@ SubDocInitEntry(PLDHashTable *table, PLDHashEntryHdr *entry, const void *key)
NS_ADDREF(e->mKey);
e->mSubDocument = nullptr;
return true;
}
nsresult

View File

@ -1,172 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set tw=80 expandtab softtabstop=2 ts=2 sw=2: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsElementFrameLoaderOwner.h"
#include "nsIDOMDocument.h"
#include "nsIInterfaceRequestorUtils.h"
#include "nsContentUtils.h"
#include "mozilla/Preferences.h"
#include "mozilla/ErrorResult.h"
#include "nsIAppsService.h"
#include "nsServiceManagerUtils.h"
#include "mozIApplication.h"
#include "nsIPermissionManager.h"
#include "GeckoProfiler.h"
#include "nsIDocument.h"
#include "nsPIDOMWindow.h"
using namespace mozilla;
using namespace mozilla::dom;
nsElementFrameLoaderOwner::~nsElementFrameLoaderOwner()
{
if (mFrameLoader) {
mFrameLoader->Destroy();
}
}
nsresult
nsElementFrameLoaderOwner::GetContentDocument(nsIDOMDocument** aContentDocument)
{
NS_PRECONDITION(aContentDocument, "Null out param");
nsCOMPtr<nsIDOMDocument> document = do_QueryInterface(GetContentDocument());
document.forget(aContentDocument);
return NS_OK;
}
nsIDocument*
nsElementFrameLoaderOwner::GetContentDocument()
{
nsCOMPtr<nsPIDOMWindow> win = GetContentWindow();
if (!win) {
return nullptr;
}
nsIDocument *doc = win->GetDoc();
// Return null for cross-origin contentDocument.
if (!nsContentUtils::SubjectPrincipal()->
SubsumesConsideringDomain(doc->NodePrincipal())) {
return nullptr;
}
return doc;
}
nsresult
nsElementFrameLoaderOwner::GetContentWindow(nsIDOMWindow** aContentWindow)
{
NS_PRECONDITION(aContentWindow, "Null out param");
nsCOMPtr<nsPIDOMWindow> window = GetContentWindow();
window.forget(aContentWindow);
return NS_OK;
}
already_AddRefed<nsPIDOMWindow>
nsElementFrameLoaderOwner::GetContentWindow()
{
EnsureFrameLoader();
if (!mFrameLoader) {
return nullptr;
}
bool depthTooGreat = false;
mFrameLoader->GetDepthTooGreat(&depthTooGreat);
if (depthTooGreat) {
// Claim to have no contentWindow
return nullptr;
}
nsCOMPtr<nsIDocShell> doc_shell;
mFrameLoader->GetDocShell(getter_AddRefs(doc_shell));
nsCOMPtr<nsPIDOMWindow> win = do_GetInterface(doc_shell);
if (!win) {
return nullptr;
}
NS_ASSERTION(win->IsOuterWindow(),
"Uh, this window should always be an outer window!");
return win.forget();
}
void
nsElementFrameLoaderOwner::EnsureFrameLoader()
{
Element* thisElement = ThisFrameElement();
if (!thisElement->IsInDoc() ||
mFrameLoader ||
mFrameLoaderCreationDisallowed) {
// If frame loader is there, we just keep it around, cached
return;
}
// Strangely enough, this method doesn't actually ensure that the
// frameloader exists. It's more of a best-effort kind of thing.
mFrameLoader = nsFrameLoader::Create(thisElement, mNetworkCreated);
if (mIsPrerendered) {
mFrameLoader->SetIsPrerendered();
}
}
NS_IMETHODIMP
nsElementFrameLoaderOwner::GetFrameLoader(nsIFrameLoader **aFrameLoader)
{
NS_IF_ADDREF(*aFrameLoader = mFrameLoader);
return NS_OK;
}
NS_IMETHODIMP_(already_AddRefed<nsFrameLoader>)
nsElementFrameLoaderOwner::GetFrameLoader()
{
nsRefPtr<nsFrameLoader> loader = mFrameLoader;
return loader.forget();
}
NS_IMETHODIMP
nsElementFrameLoaderOwner::SwapFrameLoaders(nsIFrameLoaderOwner* aOtherOwner)
{
// We don't support this yet
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsElementFrameLoaderOwner::SetIsPrerendered()
{
MOZ_ASSERT(!mFrameLoader, "Please call SetIsPrerendered before frameLoader is created");
mIsPrerendered = true;
return NS_OK;
}
nsresult
nsElementFrameLoaderOwner::LoadSrc()
{
EnsureFrameLoader();
if (!mFrameLoader) {
return NS_OK;
}
nsresult rv = mFrameLoader->LoadFrame();
#ifdef DEBUG
if (NS_FAILED(rv)) {
NS_WARNING("failed to load URL");
}
#endif
return rv;
}
void
nsElementFrameLoaderOwner::SwapFrameLoaders(nsXULElement& aOtherOwner,
ErrorResult& aError)
{
aError.Throw(NS_ERROR_NOT_IMPLEMENTED);
}

View File

@ -1,79 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set tw=80 expandtab softtabstop=2 ts=2 sw=2: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef nsElementFrameLoaderOwner_h
#define nsElementFrameLoaderOwner_h
#include "mozilla/Attributes.h"
#include "mozilla/dom/Element.h"
#include "nsIFrameLoader.h"
#include "nsIDOMEventListener.h"
#include "mozilla/dom/FromParser.h"
#include "mozilla/ErrorResult.h"
#include "nsFrameLoader.h"
namespace mozilla {
namespace dom {
class Element;
} // namespace dom
} // namespace mozilla
class nsXULElement;
/**
* A helper class for frame elements
*/
class nsElementFrameLoaderOwner : public nsIFrameLoaderOwner
{
public:
explicit nsElementFrameLoaderOwner(mozilla::dom::FromParser aFromParser)
: mNetworkCreated(aFromParser == mozilla::dom::FROM_PARSER_NETWORK)
, mIsPrerendered(false)
, mBrowserFrameListenersRegistered(false)
, mFrameLoaderCreationDisallowed(false)
{
}
virtual ~nsElementFrameLoaderOwner();
NS_DECL_NSIFRAMELOADEROWNER
// nsIContent
void SwapFrameLoaders(nsXULElement& aOtherOwner, mozilla::ErrorResult& aError);
protected:
// This doesn't really ensure a frame loader in all cases, only when
// it makes sense.
void EnsureFrameLoader();
nsresult LoadSrc();
nsIDocument* GetContentDocument();
nsresult GetContentDocument(nsIDOMDocument** aContentDocument);
already_AddRefed<nsPIDOMWindow> GetContentWindow();
nsresult GetContentWindow(nsIDOMWindow** aContentWindow);
/**
* Get element for this frame. Avoids diamond inheritance problem.
* @return Element for this node
*/
virtual mozilla::dom::Element* ThisFrameElement() = 0;
nsRefPtr<nsFrameLoader> mFrameLoader;
/**
* True when the element is created by the parser using the
* NS_FROM_PARSER_NETWORK flag.
* If the element is modified, it may lose the flag.
*/
bool mNetworkCreated;
bool mIsPrerendered;
bool mBrowserFrameListenersRegistered;
bool mFrameLoaderCreationDisallowed;
};
#endif // nsElementFrameLoaderOwner_h

View File

@ -99,9 +99,8 @@ GlobalNameHashClearEntry(PLDHashTable *table, PLDHashEntryHdr *entry)
memset(&e->mGlobalName, 0, sizeof(nsGlobalNameStruct));
}
static bool
GlobalNameHashInitEntry(PLDHashTable *table, PLDHashEntryHdr *entry,
const void *key)
static void
GlobalNameHashInitEntry(PLDHashEntryHdr *entry, const void *key)
{
GlobalNameMapEntry *e = static_cast<GlobalNameMapEntry *>(entry);
const nsAString *keyStr = static_cast<const nsAString *>(key);
@ -112,7 +111,6 @@ GlobalNameHashInitEntry(PLDHashTable *table, PLDHashEntryHdr *entry,
// This will set e->mGlobalName.mType to
// nsGlobalNameStruct::eTypeNotInitialized
memset(&e->mGlobalName, 0, sizeof(nsGlobalNameStruct));
return true;
}
NS_IMPL_ISUPPORTS(

View File

@ -42,9 +42,9 @@ NS_IMPL_RELEASE_INHERITED(nsGenericHTMLFrameElement, nsGenericHTMLElement)
NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION_INHERITED(nsGenericHTMLFrameElement)
NS_INTERFACE_TABLE_INHERITED(nsGenericHTMLFrameElement,
nsIFrameLoaderOwner,
nsIDOMMozBrowserFrame,
nsIMozBrowserFrame,
nsIFrameLoaderOwner)
nsIMozBrowserFrame)
NS_INTERFACE_TABLE_TAIL_INHERITING(nsGenericHTMLElement)
NS_IMPL_BOOL_ATTR(nsGenericHTMLFrameElement, Mozbrowser, mozbrowser)
@ -54,6 +54,96 @@ nsGenericHTMLFrameElement::TabIndexDefault()
return 0;
}
nsGenericHTMLFrameElement::~nsGenericHTMLFrameElement()
{
if (mFrameLoader) {
mFrameLoader->Destroy();
}
}
nsresult
nsGenericHTMLFrameElement::GetContentDocument(nsIDOMDocument** aContentDocument)
{
NS_PRECONDITION(aContentDocument, "Null out param");
nsCOMPtr<nsIDOMDocument> document = do_QueryInterface(GetContentDocument());
document.forget(aContentDocument);
return NS_OK;
}
nsIDocument*
nsGenericHTMLFrameElement::GetContentDocument()
{
nsCOMPtr<nsPIDOMWindow> win = GetContentWindow();
if (!win) {
return nullptr;
}
nsIDocument *doc = win->GetDoc();
// Return null for cross-origin contentDocument.
if (!nsContentUtils::SubjectPrincipal()->
SubsumesConsideringDomain(doc->NodePrincipal())) {
return nullptr;
}
return doc;
}
nsresult
nsGenericHTMLFrameElement::GetContentWindow(nsIDOMWindow** aContentWindow)
{
NS_PRECONDITION(aContentWindow, "Null out param");
nsCOMPtr<nsPIDOMWindow> window = GetContentWindow();
window.forget(aContentWindow);
return NS_OK;
}
already_AddRefed<nsPIDOMWindow>
nsGenericHTMLFrameElement::GetContentWindow()
{
EnsureFrameLoader();
if (!mFrameLoader) {
return nullptr;
}
bool depthTooGreat = false;
mFrameLoader->GetDepthTooGreat(&depthTooGreat);
if (depthTooGreat) {
// Claim to have no contentWindow
return nullptr;
}
nsCOMPtr<nsIDocShell> doc_shell;
mFrameLoader->GetDocShell(getter_AddRefs(doc_shell));
nsCOMPtr<nsPIDOMWindow> win = do_GetInterface(doc_shell);
if (!win) {
return nullptr;
}
NS_ASSERTION(win->IsOuterWindow(),
"Uh, this window should always be an outer window!");
return win.forget();
}
void
nsGenericHTMLFrameElement::EnsureFrameLoader()
{
if (!IsInDoc() || mFrameLoader || mFrameLoaderCreationDisallowed) {
// If frame loader is there, we just keep it around, cached
return;
}
// Strangely enough, this method doesn't actually ensure that the
// frameloader exists. It's more of a best-effort kind of thing.
mFrameLoader = nsFrameLoader::Create(this, mNetworkCreated);
if (mIsPrerendered) {
mFrameLoader->SetIsPrerendered();
}
}
nsresult
nsGenericHTMLFrameElement::CreateRemoteFrameLoader(nsITabParent* aTabParent)
{
@ -72,6 +162,54 @@ nsGenericHTMLFrameElement::CreateRemoteFrameLoader(nsITabParent* aTabParent)
return NS_OK;
}
NS_IMETHODIMP
nsGenericHTMLFrameElement::GetFrameLoader(nsIFrameLoader **aFrameLoader)
{
NS_IF_ADDREF(*aFrameLoader = mFrameLoader);
return NS_OK;
}
NS_IMETHODIMP_(already_AddRefed<nsFrameLoader>)
nsGenericHTMLFrameElement::GetFrameLoader()
{
nsRefPtr<nsFrameLoader> loader = mFrameLoader;
return loader.forget();
}
NS_IMETHODIMP
nsGenericHTMLFrameElement::SwapFrameLoaders(nsIFrameLoaderOwner* aOtherOwner)
{
// We don't support this yet
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsGenericHTMLFrameElement::SetIsPrerendered()
{
MOZ_ASSERT(!mFrameLoader, "Please call SetIsPrerendered before frameLoader is created");
mIsPrerendered = true;
return NS_OK;
}
nsresult
nsGenericHTMLFrameElement::LoadSrc()
{
EnsureFrameLoader();
if (!mFrameLoader) {
return NS_OK;
}
nsresult rv = mFrameLoader->LoadFrame();
#ifdef DEBUG
if (NS_FAILED(rv)) {
NS_WARNING("failed to load URL");
}
#endif
return rv;
}
nsresult
nsGenericHTMLFrameElement::BindToTree(nsIDocument* aDocument,
nsIContent* aParent,
@ -507,3 +645,11 @@ nsGenericHTMLFrameElement::InitializeBrowserAPI()
InitBrowserElementAPI();
return NS_OK;
}
void
nsGenericHTMLFrameElement::SwapFrameLoaders(nsXULElement& aOtherOwner,
ErrorResult& aError)
{
aError.Throw(NS_ERROR_NOT_IMPLEMENTED);
}

View File

@ -12,7 +12,6 @@
#include "mozilla/ErrorResult.h"
#include "mozilla/dom/nsBrowserElement.h"
#include "nsElementFrameLoaderOwner.h"
#include "nsFrameLoader.h"
#include "nsGenericHTMLElement.h"
#include "nsIDOMEventListener.h"
@ -25,7 +24,7 @@ class nsXULElement;
* A helper class for frame elements
*/
class nsGenericHTMLFrameElement : public nsGenericHTMLElement,
public nsElementFrameLoaderOwner,
public nsIFrameLoaderOwner,
public mozilla::nsBrowserElement,
public nsIMozBrowserFrame
{
@ -33,13 +32,17 @@ public:
nsGenericHTMLFrameElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo,
mozilla::dom::FromParser aFromParser)
: nsGenericHTMLElement(aNodeInfo)
, nsElementFrameLoaderOwner(aFromParser)
, nsBrowserElement()
, mNetworkCreated(aFromParser == mozilla::dom::FROM_PARSER_NETWORK)
, mIsPrerendered(false)
, mBrowserFrameListenersRegistered(false)
, mFrameLoaderCreationDisallowed(false)
{
}
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_NSIFRAMELOADEROWNER
NS_DECL_NSIDOMMOZBROWSERFRAME
NS_DECL_NSIMOZBROWSERFRAME
@ -72,20 +75,9 @@ public:
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED_NO_UNLINK(nsGenericHTMLFrameElement,
nsGenericHTMLElement)
static bool BrowserFramesEnabled();
void SwapFrameLoaders(nsXULElement& aOtherOwner, mozilla::ErrorResult& aError);
/**
* nsIFrameLoaderOwner defines two GetFrameLoader() overloads. One
* is XPCOM style interface, the other one is C++ only. "using" pulls
* them both in, now GetFrameLoader() is ambiguous because
* nsBrowserElement also has GetFrameLoader(). Explicit redefine
* GetFrameLoader() to choose nsElementFrameLoaderOwner::GetFrameLoader()
*/
using nsElementFrameLoaderOwner::GetFrameLoader;
NS_IMETHOD_(already_AddRefed<nsFrameLoader>) GetFrameLoader() MOZ_OVERRIDE
{
return nsElementFrameLoaderOwner::GetFrameLoader();
}
static bool BrowserFramesEnabled();
/**
* Helper method to map a HTML 'scrolling' attribute value to a nsIScrollable
@ -98,12 +90,29 @@ public:
static int32_t MapScrollingAttribute(const nsAttrValue* aValue);
protected:
virtual ~nsGenericHTMLFrameElement() {}
virtual ~nsGenericHTMLFrameElement();
virtual mozilla::dom::Element* ThisFrameElement() MOZ_OVERRIDE
{
return this;
}
// This doesn't really ensure a frame loader in all cases, only when
// it makes sense.
void EnsureFrameLoader();
nsresult LoadSrc();
nsIDocument* GetContentDocument();
nsresult GetContentDocument(nsIDOMDocument** aContentDocument);
already_AddRefed<nsPIDOMWindow> GetContentWindow();
nsresult GetContentWindow(nsIDOMWindow** aContentWindow);
nsRefPtr<nsFrameLoader> mFrameLoader;
/**
* True when the element is created by the parser using the
* NS_FROM_PARSER_NETWORK flag.
* If the element is modified, it may lose the flag.
*/
bool mNetworkCreated;
bool mIsPrerendered;
bool mBrowserFrameListenersRegistered;
bool mFrameLoaderCreationDisallowed;
private:
void GetManifestURLByType(nsIAtom *aAppType, nsAString& aOut);

View File

@ -141,7 +141,7 @@ void VideoFrameContainer::InvalidateWithFlags(uint32_t aFlags)
if (invalidateFrame) {
frame->InvalidateFrame();
} else {
frame->InvalidateLayer(nsDisplayItem::TYPE_VIDEO, nullptr,
frame->InvalidateLayer(nsDisplayItem::TYPE_VIDEO, nullptr, nullptr,
asyncInvalidate ? nsIFrame::UPDATE_IS_ASYNC : 0);
}
}

View File

@ -65,23 +65,6 @@ TrackBuffer::~TrackBuffer()
MOZ_COUNT_DTOR(TrackBuffer);
}
class ReleaseDecoderTask : public nsRunnable {
public:
explicit ReleaseDecoderTask(SourceBufferDecoder* aDecoder)
: mDecoder(aDecoder)
{
}
NS_IMETHOD Run() MOZ_OVERRIDE MOZ_FINAL {
mDecoder->GetReader()->BreakCycles();
mDecoder = nullptr;
return NS_OK;
}
private:
nsRefPtr<SourceBufferDecoder> mDecoder;
};
class MOZ_STACK_CLASS DecodersToInitialize MOZ_FINAL {
public:
explicit DecodersToInitialize(TrackBuffer* aOwner)
@ -153,7 +136,7 @@ TrackBuffer::ContinueShutdown()
return;
}
mCurrentDecoder = nullptr;
MOZ_ASSERT(!mCurrentDecoder, "Detach() should have been called");
mInitializedDecoders.Clear();
mParentDecoder = nullptr;
@ -691,6 +674,7 @@ TrackBuffer::RegisterDecoder(SourceBufferDecoder* aDecoder)
void
TrackBuffer::DiscardCurrentDecoder()
{
MOZ_ASSERT(NS_IsMainThread());
ReentrantMonitorAutoEnter mon(mParentDecoder->GetReentrantMonitor());
EndCurrentDecoder();
mCurrentDecoder = nullptr;
@ -842,10 +826,34 @@ TrackBuffer::Dump(const char* aPath)
}
#endif
class ReleaseDecoderTask : public nsRunnable {
public:
ReleaseDecoderTask(SourceBufferDecoder* aDecoder, TrackBuffer* aTrackBuffer)
: mDecoder(aDecoder)
, mTrackBuffer(aTrackBuffer)
{
}
NS_IMETHOD Run() MOZ_OVERRIDE MOZ_FINAL {
if (mTrackBuffer->mCurrentDecoder == mDecoder) {
mTrackBuffer->DiscardCurrentDecoder();
}
mDecoder->GetReader()->BreakCycles();
mDecoder = nullptr;
return NS_OK;
}
private:
nsRefPtr<SourceBufferDecoder> mDecoder;
nsRefPtr<TrackBuffer> mTrackBuffer;
};
class DelayedDispatchToMainThread : public nsRunnable {
public:
explicit DelayedDispatchToMainThread(SourceBufferDecoder* aDecoder)
DelayedDispatchToMainThread(SourceBufferDecoder* aDecoder, TrackBuffer* aTrackBuffer)
: mDecoder(aDecoder)
, mTrackBuffer(aTrackBuffer)
{
}
@ -855,7 +863,7 @@ public:
// is destroyed.
mDecoder->GetReader()->Shutdown();
mDecoder->GetReader()->ClearDecoder();
RefPtr<nsIRunnable> task = new ReleaseDecoderTask(mDecoder);
RefPtr<nsIRunnable> task = new ReleaseDecoderTask(mDecoder, mTrackBuffer);
mDecoder = nullptr;
// task now holds the only ref to the decoder.
NS_DispatchToMainThread(task);
@ -863,14 +871,15 @@ public:
}
private:
RefPtr<SourceBufferDecoder> mDecoder;
nsRefPtr<SourceBufferDecoder> mDecoder;
nsRefPtr<TrackBuffer> mTrackBuffer;
};
void
TrackBuffer::RemoveDecoder(SourceBufferDecoder* aDecoder)
{
RefPtr<nsIRunnable> task = new DelayedDispatchToMainThread(aDecoder);
MSE_DEBUG("TrackBuffer(%p)::RemoveDecoder(%p, %p)", this, aDecoder, aDecoder->GetReader());
RefPtr<nsIRunnable> task = new DelayedDispatchToMainThread(aDecoder, this);
{
ReentrantMonitorAutoEnter mon(mParentDecoder->GetReentrantMonitor());
// There should be no other references to the decoder. Assert that
@ -878,10 +887,6 @@ TrackBuffer::RemoveDecoder(SourceBufferDecoder* aDecoder)
MOZ_ASSERT(!mParentDecoder->IsActiveReader(aDecoder->GetReader()));
mInitializedDecoders.RemoveElement(aDecoder);
mDecoders.RemoveElement(aDecoder);
if (mCurrentDecoder == aDecoder) {
DiscardCurrentDecoder();
}
}
aDecoder->GetReader()->GetTaskQueue()->Dispatch(task);
}

View File

@ -61,7 +61,7 @@ public:
double Buffered(dom::TimeRanges* aRanges);
// Mark the current decoder's resource as ended, clear mCurrentDecoder and
// reset mLast{Start,End}Timestamp.
// reset mLast{Start,End}Timestamp. Main thread only.
void DiscardCurrentDecoder();
// Mark the current decoder's resource as ended.
void EndCurrentDecoder();
@ -114,6 +114,7 @@ public:
private:
friend class DecodersToInitialize;
friend class ReleaseDecoderTask;
~TrackBuffer();
// Create a new decoder, set mCurrentDecoder to the new decoder and
@ -181,6 +182,7 @@ private:
nsTArray<nsRefPtr<SourceBufferDecoder>> mWaitingDecoders;
// The decoder that the owning SourceBuffer is currently appending data to.
// Modified on the main thread only.
nsRefPtr<SourceBufferDecoder> mCurrentDecoder;
nsRefPtr<MediaSourceDecoder> mParentDecoder;

View File

@ -34,7 +34,8 @@ RequestSyncManager.prototype = {
Ci.nsIDOMGlobalPropertyInitializer]),
_messages: [ "RequestSyncManager:Registrations:Return",
"RequestSyncManager:SetPolicy:Return" ],
"RequestSyncManager:SetPolicy:Return",
"RequestSyncManager:RunTask:Return" ],
init: function(aWindow) {
debug("init");
@ -71,6 +72,16 @@ RequestSyncManager.prototype = {
overwrittenMinInterval: aOverwrittenMinInterval });
},
runTask: function(aTask, aOrigin, aManifestURL, aIsInBrowserElement) {
debug('runTask');
return this.sendMessage("RequestSyncManager:RunTask",
{ task: aTask,
origin: aOrigin,
manifestURL: aManifestURL,
isInBrowserElement: aIsInBrowserElement });
},
registrationsResult: function(aData) {
debug("registrationsResult");

View File

@ -56,7 +56,8 @@ this.RequestSyncService = {
"RequestSync:Registrations",
"RequestSync:Registration",
"RequestSyncManager:Registrations",
"RequestSyncManager:SetPolicy" ],
"RequestSyncManager:SetPolicy",
"RequestSyncManager:RunTask" ],
_pendingOperation: false,
_pendingMessages: [],
@ -327,6 +328,10 @@ this.RequestSyncService = {
this.managerSetPolicy(aMessage.target, aMessage.data, principal);
break;
case "RequestSyncManager:RunTask":
this.managerRunTask(aMessage.target, aMessage.data, principal);
break;
default:
debug("Wrong message: " + aMessage.name);
break;
@ -397,7 +402,8 @@ this.RequestSyncService = {
dbKey: dbKey,
data: aData.params,
active: true,
timer: null };
timer: null,
requestIDs: [] };
let self = this;
this.dbTxn('readwrite', function(aStore) {
@ -503,6 +509,10 @@ this.RequestSyncService = {
let toSave = null;
let self = this;
this.forEachRegistration(function(aObj) {
if (aObj.data.task != aData.task) {
return;
}
if (aObj.principal.isInBrowserElement != aData.isInBrowserElement ||
aObj.principal.origin != aData.origin) {
return;
@ -541,6 +551,46 @@ this.RequestSyncService = {
});
},
// Run a task now.
managerRunTask: function(aTarget, aData, aPrincipal) {
debug("runTask");
let task = null;
this.forEachRegistration(function(aObj) {
if (aObj.data.task != aData.task) {
return;
}
if (aObj.principal.isInBrowserElement != aData.isInBrowserElement ||
aObj.principal.origin != aData.origin) {
return;
}
let app = appsService.getAppByLocalId(aObj.principal.appId);
if (app && app.manifestURL != aData.manifestURL ||
(!app && aData.manifestURL != "")) {
return;
}
if (task) {
dump("ERROR!! RequestSyncService - RunTask matches more than 1 task.\n");
return;
}
task = aObj;
});
if (!task) {
aTarget.sendAsyncMessage("RequestSyncManager:RunTask:Return",
{ requestID: aData.requestID, error: "UnknownTaskError" });
return;
}
// Storing the requestID into the task for the callback.
task.requestIDs.push({ target: aTarget, requestID: aData.requestID });
this.timeout(task);
},
// We cannot expose the full internal object to content but just a subset.
// This method creates this subset.
createPartialTaskObject: function(aObj) {
@ -705,6 +755,16 @@ this.RequestSyncService = {
this._activeTask.active = !this._activeTask.data.oneShot;
this._activeTask.data.lastSync = new Date();
if (this._activeTask.requestIDs.length) {
for (let i = 0; i < this._activeTask.requestIDs.length; ++i) {
this._activeTask.requestIDs[i]
.target.sendAsyncMessage("RequestSyncManager:RunTask:Return",
{ requestID: this._activeTask.requestIDs[i].requestID });
}
this._activeTask.requestIDs = [];
}
let self = this;
this.updateObjectInDB(this._activeTask, function() {
// SchedulerTimer creates a timer and a nsITimer cannot be cloned. This

View File

@ -97,5 +97,12 @@ this.RequestSyncTask.prototype = {
aResolve();
}, aReject);
});
},
runNow: function() {
debug("runNow");
return this._manager.runTask(this._task, this._app.origin,
this._app.manifestURL,
this._app.isInBrowserElement);
}
};

View File

@ -169,6 +169,7 @@ function test_managerRegistrations(state, overwrittenMinInterval) {
is(results[0].state, state, "navigator.sync.registrations()[0].state is correct");
is(results[0].overwrittenMinInterval, overwrittenMinInterval, "navigator.sync.registrations()[0].overwrittenMinInterval is correct");
ok("setPolicy" in results[0], "navigator.sync.registrations()[0].setPolicy is correct");
ok("runNow" in results[0], "navigator.sync.registrations()[0].runNow is correct");
runTests();
},
genericError);

View File

@ -14,4 +14,6 @@ support-files =
run-if = buildapp != 'b2g'
[test_wakeUp.html]
run-if = buildapp == 'b2g' && toolkit == 'gonk'
[test_runNow.html]
run-if = buildapp == 'b2g' && toolkit == 'gonk'
[test_promise.html]

View File

@ -19,7 +19,13 @@
is(e, "ParamsError", "Correct error received");
})
.then(runTests);
.then(function() {
if (expected) {
navigator.sync.unregister('foobar').then(runTests);
} else {
runTests();
}
});
}
var tests = [

View File

@ -0,0 +1,111 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Test for requestSync - runNow</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript" src="common_basic.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<div id="container"></div>
<script type="application/javascript;version=1.7">
var taskExecuted = false;
function setMessageHandler() {
navigator.mozSetMessageHandler('request-sync', function(e) {
ok(true, "One event has been received!");
if (e.task == "oneShot") {
is(e.data, 42, "e.data is correct");
is(e.lastSync, 0, "e.lastSync is correct");
is(e.oneShot, true, "e.oneShot is correct");
is(e.minInterval, 1024, "e.minInterval is correct");
is(e.wifiOnly, false, "e.wifiOnly is correct");
taskExecuted = true;
} else {
ok(false, "Unknown event has been received!");
}
});
runTests();
}
function test_register_oneShot() {
navigator.sync.register('oneShot', { minInterval: 1024,
oneShot: true,
data: 42,
wifiOnly: false,
wakeUpPage: location.href }).then(
function() {
ok(true, "navigator.sync.register() oneShot done");
runTests();
}, genericError);
}
function test_unregister_oneShot() {
navigator.sync.unregister('oneShot').then(
function() {
ok(true, "navigator.sync.unregister() oneShot done");
runTests();
}, genericError);
}
function test_runNow() {
navigator.syncManager.registrations().then(
function(array) {
for (var i = 0; i < array.length; ++i) { info(array[i].task); }
is(array.length, 1, "One registration found.");
array[0].runNow().then(function() {
ok(taskExecuted, "Task has been executed");
runTests();
});
}, genericError);
}
var tests = [
function() {
SpecialPowers.pushPrefEnv({"set": [["dom.sysmsg.enabled", true],
["dom.requestSync.enabled", true],
["dom.requestSync.minInterval", 1],
["dom.requestSync.maxTaskTimeout", 10000 /* 10 seconds */],
["dom.ignore_webidl_scope_checks", true]]}, runTests);
},
function() {
SpecialPowers.pushPermissions(
[{ "type": "requestsync-manager", "allow": 1, "context": document } ], runTests);
},
function() {
if (SpecialPowers.isMainProcess()) {
SpecialPowers.Cu.import("resource://gre/modules/RequestSyncService.jsm");
}
runTests();
},
setMessageHandler,
test_register_oneShot,
test_runNow,
test_unregister_oneShot,
];
function runTests() {
if (!tests.length) {
SimpleTest.finish();
return;
}
var test = tests.shift();
test();
}
SimpleTest.waitForExplicitFinish();
runTests();
</script>
</body>
</html>

View File

@ -41,6 +41,8 @@ interface RequestSyncTask {
Promise<void> setPolicy(RequestSyncTaskPolicyState aState,
optional long ovewrittenMinInterval);
Promise<void> runNow();
};
[NavigatorProperty="syncManager",

View File

@ -169,7 +169,6 @@ void nsPNGDecoder::CreateFrame(png_uint_32 x_offset, png_uint_32 y_offset,
}
mFrameRect = neededRect;
mFrameHasNoAlpha = true;
PR_LOG(GetPNGDecoderAccountingLog(), PR_LOG_DEBUG,
("PNGDecoderAccounting: nsPNGDecoder::CreateFrame -- created "
@ -201,7 +200,7 @@ nsPNGDecoder::EndImageFrame()
mNumFrames++;
Opacity opacity = Opacity::SOME_TRANSPARENCY;
if (format == gfx::SurfaceFormat::B8G8R8X8 || mFrameHasNoAlpha) {
if (format == gfx::SurfaceFormat::B8G8R8X8) {
opacity = Opacity::OPAQUE;
}
@ -739,7 +738,6 @@ nsPNGDecoder::row_callback(png_structp png_ptr, png_bytep new_row,
uint32_t bpr = width * sizeof(uint32_t);
uint32_t* cptr32 = (uint32_t*)(decoder->mImageData + (row_num*bpr));
bool rowHasNoAlpha = true;
if (decoder->mTransform) {
if (decoder->mCMSLine) {
@ -788,18 +786,12 @@ nsPNGDecoder::row_callback(png_structp png_ptr, png_bytep new_row,
if (!decoder->mDisablePremultipliedAlpha) {
for (uint32_t x=width; x>0; --x) {
*cptr32++ = gfxPackedPixel(line[3], line[0], line[1], line[2]);
if (line[3] != 0xff) {
rowHasNoAlpha = false;
}
line += 4;
}
} else {
for (uint32_t x=width; x>0; --x) {
*cptr32++ = gfxPackedPixelNoPreMultiply(line[3], line[0], line[1],
line[2]);
if (line[3] != 0xff) {
rowHasNoAlpha = false;
}
line += 4;
}
}
@ -809,10 +801,6 @@ nsPNGDecoder::row_callback(png_structp png_ptr, png_bytep new_row,
png_longjmp(decoder->mPNG, 1);
}
if (!rowHasNoAlpha) {
decoder->mFrameHasNoAlpha = false;
}
if (decoder->mNumFrames <= 1) {
// Only do incremental image display for the first frame
// XXXbholley - this check should be handled in the superclass

View File

@ -86,7 +86,6 @@ public:
uint32_t mCMSMode;
uint8_t mChannels;
bool mFrameHasNoAlpha;
bool mFrameIsHidden;
bool mDisablePremultipliedAlpha;

View File

@ -0,0 +1,59 @@
if (getJitCompilerOptions()["ion.warmup.trigger"] > 50)
setJitCompilerOption("ion.warmup.trigger", 50);
function getObjects() {
var objs = [];
// Own scripted getter/setter.
objs.push({x: 0, get prop() {
assertJitStackInvariants();
return ++this.x;
}, set prop(v) {
assertJitStackInvariants();
this.x += v;
}});
// Scripted getter/setter on prototype. Also verify extra formal args are
// handled correctly.
function getter(a, b, c) {
assertEq(arguments.length, 0);
assertEq(a, undefined);
assertEq(b, undefined);
assertEq(c, undefined);
assertJitStackInvariants();
bailout();
return ++this.y;
}
function setter1(a, b) {
assertEq(arguments.length, 1);
assertEq(b, undefined);
assertJitStackInvariants();
this.y = a;
bailout();
return "unused";
}
var proto = {};
Object.defineProperty(proto, "prop", {get: getter, set: setter1});
objs.push(Object.create(proto));
function setter2() {
assertEq(arguments.length, 1);
assertJitStackInvariants();
this.y = arguments[0];
}
proto = {};
Object.defineProperty(proto, "prop", {get: getter, set: setter2});
objs.push(Object.create(proto));
return objs;
}
function f() {
var objs = getObjects();
var res = 0;
for (var i=0; i<200; i++) {
var o = objs[i % objs.length];
o.prop = 2;
res += o.prop;
}
assertEq(res, 7233);
}
f();

View File

@ -0,0 +1,32 @@
// Ensure readSPSProfilingStack() doesn't crash with Ion
// getter/setter ICs on the stack.
function getObjects() {
var objs = [];
objs.push({x: 0, get prop() {
readSPSProfilingStack();
return ++this.x;
}, set prop(v) {
readSPSProfilingStack();
this.x = v + 2;
}});
objs.push({x: 0, y: 0, get prop() {
readSPSProfilingStack();
return this.y;
}, set prop(v) {
readSPSProfilingStack();
this.y = v;
}});
return objs;
}
function f() {
var objs = getObjects();
var res = 0;
for (var i=0; i<100; i++) {
var o = objs[i % objs.length];
res += o.prop;
o.prop = i;
}
assertEq(res, 4901);
}
enableSPSProfiling();
f();

View File

@ -5,6 +5,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "jsprf.h"
#include "jsutil.h"
#include "jit/arm/Simulator-arm.h"
#include "jit/BaselineIC.h"
#include "jit/BaselineJIT.h"
@ -239,6 +240,18 @@ struct BaselineStackBuilder
return true;
}
bool maybeWritePadding(size_t alignment, size_t after, const char *info) {
MOZ_ASSERT(framePushed_ % sizeof(Value) == 0);
MOZ_ASSERT(after % sizeof(Value) == 0);
size_t offset = ComputeByteAlignment(after, alignment);
while (framePushed_ % alignment != offset) {
if (!writeValue(MagicValue(JS_ARG_POISON), info))
return false;
}
return true;
}
Value popValue() {
MOZ_ASSERT(bufferUsed_ >= sizeof(Value));
MOZ_ASSERT(framePushed_ >= sizeof(Value));
@ -329,10 +342,11 @@ struct BaselineStackBuilder
BufferPointer<JitFrameLayout> topFrame = topFrameAddress();
FrameType type = topFrame->prevType();
// For IonJS and Entry frames, the "saved" frame pointer in the baseline
// frame is meaningless, since Ion saves all registers before calling other ion
// frames, and the entry frame saves all registers too.
if (type == JitFrame_IonJS || type == JitFrame_Entry)
// For IonJS, IonAccessorIC and Entry frames, the "saved" frame pointer
// in the baseline frame is meaningless, since Ion saves all registers
// before calling other ion frames, and the entry frame saves all
// registers too.
if (type == JitFrame_IonJS || type == JitFrame_Entry || type == JitFrame_IonAccessorIC)
return nullptr;
// BaselineStub - Baseline calling into Ion.
@ -506,11 +520,13 @@ HasLiveIteratorAtStackDepth(JSScript *script, jsbytecode *pc, uint32_t stackDept
// | | | StubPtr |
// | | +---------------+
// | +---| FramePtr |
// | +---------------+ --- The inlined frame might OSR in Ion
// | | Padding? | --- Thus the return address should be aligned.
// | +---------------+
// | | ArgA |
// | +---------------+
// | | ... |
// +--< +---------------+
// +--< | ArgA |
// | | +---------------+
// | | | ... |
// | | +---------------+
// | | | Arg0 |
// | | +---------------+
// | | | ThisV |
@ -523,13 +539,15 @@ HasLiveIteratorAtStackDepth(JSScript *script, jsbytecode *pc, uint32_t stackDept
// +---------------+
// | ReturnAddr | <-- return into ICCall_Scripted IC
// -- +===============+ --- IF CALLEE FORMAL ARGS > ActualArgC
// | | Padding? |
// | +---------------+
// | | UndefinedU |
// | +---------------+
// | | ... |
// | +---------------+
// | | Undefined0 |
// | +---------------+
// +--< | ArgA |
// +--< +---------------+
// | | | ArgA |
// | | +---------------+
// | | | ... |
// | | +---------------+
@ -1136,6 +1154,8 @@ InitFromBailout(JSContext *cx, HandleScript caller, jsbytecode *callerPC,
// +---------------+
// | FramePtr |
// +---------------+
// | Padding? |
// +---------------+
// | ArgA |
// +---------------+
// | ... |
@ -1179,6 +1199,12 @@ InitFromBailout(JSContext *cx, HandleScript caller, jsbytecode *callerPC,
else
actualArgc = IsSetPropPC(pc);
// Align the stack based on the number of arguments.
size_t afterFrameSize = (actualArgc + 1) * sizeof(Value) + JitFrameLayout::Size();
if (!builder.maybeWritePadding(JitStackAlignment, afterFrameSize, "Padding"))
return false;
// Push arguments.
MOZ_ASSERT(actualArgc + 2 <= exprStackSlots);
MOZ_ASSERT(savedCallerArgs.length() == actualArgc + 2);
for (unsigned i = 0; i < actualArgc + 1; i++) {
@ -1193,6 +1219,11 @@ InitFromBailout(JSContext *cx, HandleScript caller, jsbytecode *callerPC,
actualArgc--;
}
// Align the stack based on the number of arguments.
size_t afterFrameSize = (actualArgc + 1) * sizeof(Value) + JitFrameLayout::Size();
if (!builder.maybeWritePadding(JitStackAlignment, afterFrameSize, "Padding"))
return false;
MOZ_ASSERT(actualArgc + 2 <= exprStackSlots);
for (unsigned i = 0; i < actualArgc + 1; i++) {
size_t argSlot = (script->nfixed() + exprStackSlots) - (i + 1);
@ -1243,6 +1274,7 @@ InitFromBailout(JSContext *cx, HandleScript caller, jsbytecode *callerPC,
MOZ_ASSERT(baselineCallReturnAddr);
if (!builder.writePtr(baselineCallReturnAddr, "ReturnAddr"))
return false;
MOZ_ASSERT(builder.framePushed() % JitStackAlignment == 0);
// If actualArgc >= fun->nargs, then we are done. Otherwise, we need to push on
// a reconstructed rectifier frame.
@ -1251,6 +1283,8 @@ InitFromBailout(JSContext *cx, HandleScript caller, jsbytecode *callerPC,
// Push a reconstructed rectifier frame.
// +===============+
// | Padding? |
// +---------------+
// | UndefinedU |
// +---------------+
// | ... |
@ -1282,8 +1316,17 @@ InitFromBailout(JSContext *cx, HandleScript caller, jsbytecode *callerPC,
#if defined(JS_CODEGEN_X86)
if (!builder.writePtr(prevFramePtr, "PrevFramePtr-X86Only"))
return false;
// Follow the same logic as in JitRuntime::generateArgumentsRectifier.
prevFramePtr = builder.virtualPointerAtStackOffset(0);
if (!builder.writePtr(prevFramePtr, "Padding-X86Only"))
return false;
#endif
// Align the stack based on the number of arguments.
size_t afterFrameSize = (calleeFun->nargs() + 1) * sizeof(Value) + RectifierFrameLayout::Size();
if (!builder.maybeWritePadding(JitStackAlignment, afterFrameSize, "Padding"))
return false;
// Push undefined for missing arguments.
for (unsigned i = 0; i < (calleeFun->nargs() - actualArgc); i++) {
if (!builder.writeValue(UndefinedValue(), "FillerVal"))
@ -1322,6 +1365,7 @@ InitFromBailout(JSContext *cx, HandleScript caller, jsbytecode *callerPC,
MOZ_ASSERT(rectReturnAddr);
if (!builder.writePtr(rectReturnAddr, "ReturnAddr"))
return false;
MOZ_ASSERT(builder.framePushed() % JitStackAlignment == 0);
return true;
}
@ -1348,7 +1392,8 @@ jit::BailoutIonToBaseline(JSContext *cx, JitActivation *activation, JitFrameIter
MOZ_ASSERT(prevFrameType == JitFrame_IonJS ||
prevFrameType == JitFrame_BaselineStub ||
prevFrameType == JitFrame_Entry ||
prevFrameType == JitFrame_Rectifier);
prevFrameType == JitFrame_Rectifier ||
prevFrameType == JitFrame_IonAccessorIC);
// All incoming frames are going to look like this:
//

View File

@ -2507,10 +2507,14 @@ InvalidateActivation(FreeOp *fop, const JitActivationIterator &activations, bool
case JitFrame_Unwound_IonJS:
case JitFrame_Unwound_BaselineJS:
case JitFrame_Unwound_BaselineStub:
case JitFrame_Unwound_IonAccessorIC:
MOZ_CRASH("invalid");
case JitFrame_Unwound_Rectifier:
JitSpew(JitSpew_IonInvalidate, "#%d unwound rectifier frame @ %p", frameno, it.fp());
break;
case JitFrame_IonAccessorIC:
JitSpew(JitSpew_IonInvalidate, "#%d ion IC getter/setter frame @ %p", frameno, it.fp());
break;
case JitFrame_Entry:
JitSpew(JitSpew_IonInvalidate, "#%d entry frame @ %p", frameno, it.fp());
break;

View File

@ -7765,7 +7765,6 @@ IonBuilder::pushDerivedTypedObject(bool *emitted,
// describes.
TemporaryTypeSet *observedTypes = bytecodeTypes(pc);
const Class *observedClass = observedTypes->getKnownClass(constraints());
JSObject *observedProto = observedTypes->getCommonPrototype(constraints());
// If expectedClass/expectedProto are both non-null (and hence known), we
// can predict precisely what object group derivedTypedObj will have.
@ -7784,7 +7783,9 @@ IonBuilder::pushDerivedTypedObject(bool *emitted,
//
// Barriers are particularly expensive here because they prevent
// us from optimizing the MNewDerivedTypedObject away.
if (observedClass && observedProto && observedClass == expectedClass &&
JSObject *observedProto;
if (observedTypes->getCommonPrototype(constraints(), &observedProto) &&
observedClass && observedProto && observedClass == expectedClass &&
observedProto == expectedProto)
{
derivedTypedObj->setResultTypeSet(observedTypes);

View File

@ -652,6 +652,26 @@ IsCacheableGetPropCallNative(JSObject *obj, JSObject *holder, Shape *shape)
return !obj->getClass()->ext.outerObject;
}
static bool
IsCacheableGetPropCallScripted(JSObject *obj, JSObject *holder, Shape *shape)
{
if (!shape || !IsCacheableProtoChainForIon(obj, holder))
return false;
if (!shape->hasGetterValue() || !shape->getterValue().isObject())
return false;
if (!shape->getterValue().toObject().is<JSFunction>())
return false;
JSFunction& getter = shape->getterValue().toObject().as<JSFunction>();
if (!getter.hasJITCode())
return false;
// See IsCacheableGetPropCallNative.
return !obj->getClass()->ext.outerObject;
}
static bool
IsCacheableGetPropCallPropertyOp(JSObject *obj, JSObject *holder, Shape *shape)
{
@ -920,20 +940,15 @@ EmitGetterCall(JSContext *cx, MacroAssembler &masm,
// to try so hard to not use the stack. Scratch regs are just taken from the register
// set not including the input, current value saved on the stack, and restored when
// we're done with it.
Register scratchReg = regSet.takeGeneral();
Register argJSContextReg = regSet.takeGeneral();
Register argUintNReg = regSet.takeGeneral();
Register argVpReg = regSet.takeGeneral();
Register scratchReg = regSet.takeGeneral();
// Shape has a getter function.
bool callNative = IsCacheableGetPropCallNative(obj, holder, shape);
MOZ_ASSERT_IF(!callNative, IsCacheableGetPropCallPropertyOp(obj, holder, shape));
// Shape has a JSNative, PropertyOp or scripted getter function.
if (IsCacheableGetPropCallNative(obj, holder, shape)) {
Register argJSContextReg = regSet.takeGeneral();
Register argUintNReg = regSet.takeGeneral();
Register argVpReg = regSet.takeGeneral();
if (callNative) {
MOZ_ASSERT(shape->hasGetterValue() && shape->getterValue().isObject() &&
shape->getterValue().toObject().is<JSFunction>());
JSFunction *target = &shape->getterValue().toObject().as<JSFunction>();
MOZ_ASSERT(target);
MOZ_ASSERT(target->isNative());
@ -977,7 +992,10 @@ EmitGetterCall(JSContext *cx, MacroAssembler &masm,
// masm.leaveExitFrame & pop locals
masm.adjustStack(IonOOLNativeExitFrameLayout::Size(0));
} else {
} else if (IsCacheableGetPropCallPropertyOp(obj, holder, shape)) {
Register argJSContextReg = regSet.takeGeneral();
Register argUintNReg = regSet.takeGeneral();
Register argVpReg = regSet.takeGeneral();
Register argObjReg = argUintNReg;
Register argIdReg = regSet.takeGeneral();
@ -1023,6 +1041,51 @@ EmitGetterCall(JSContext *cx, MacroAssembler &masm,
// masm.leaveExitFrame & pop locals.
masm.adjustStack(IonOOLPropertyOpExitFrameLayout::Size());
} else {
MOZ_ASSERT(IsCacheableGetPropCallScripted(obj, holder, shape));
JSFunction *target = &shape->getterValue().toObject().as<JSFunction>();
uint32_t framePushedBefore = masm.framePushed();
// Construct IonAccessorICFrameLayout.
uint32_t descriptor = MakeFrameDescriptor(masm.framePushed(), JitFrame_IonJS);
attacher.pushStubCodePointer(masm);
masm.Push(Imm32(descriptor));
masm.Push(ImmPtr(returnAddr));
// The JitFrameLayout pushed below will be aligned to JitStackAlignment,
// so we just have to make sure the stack is aligned after we push the
// |this| + argument Values.
uint32_t argSize = (target->nargs() + 1) * sizeof(Value);
uint32_t padding = ComputeByteAlignment(masm.framePushed() + argSize, JitStackAlignment);
MOZ_ASSERT(padding % sizeof(uintptr_t) == 0);
MOZ_ASSERT(padding < JitStackAlignment);
masm.reserveStack(padding);
for (size_t i = 0; i < target->nargs(); i++)
masm.Push(UndefinedValue());
masm.Push(TypedOrValueRegister(MIRType_Object, AnyRegister(object)));
masm.movePtr(ImmMaybeNurseryPtr(target), scratchReg);
descriptor = MakeFrameDescriptor(argSize + padding, JitFrame_IonAccessorIC);
masm.Push(Imm32(0)); // argc
masm.Push(scratchReg);
masm.Push(Imm32(descriptor));
// Check stack alignment. Add sizeof(uintptr_t) for the return address.
MOZ_ASSERT(((masm.framePushed() + sizeof(uintptr_t)) % JitStackAlignment) == 0);
// The getter has JIT code now and we will only discard the getter's JIT
// code when discarding all JIT code in the Zone, so we can assume it'll
// still have JIT code.
MOZ_ASSERT(target->hasJITCode());
masm.loadPtr(Address(scratchReg, JSFunction::offsetOfNativeOrScript()), scratchReg);
masm.loadBaselineOrIonRaw(scratchReg, scratchReg, nullptr);
masm.callJit(scratchReg);
masm.storeCallResultValue(output);
masm.freeStack(masm.framePushed() - framePushedBefore);
}
masm.icRestoreLive(liveRegs, aic);
@ -1240,12 +1303,13 @@ CanAttachNativeGetProp(typename GetPropCache::Context cx, const GetPropCache &ca
//
// Be careful when adding support for other getters here: for outer window
// proxies, IonBuilder can innerize and pass us the inner window (the global),
// see IonBuilder::getPropTryInnerize. This is fine for native getters because
// IsCacheableGetPropCallNative checks they can handle both the inner and
// outer object, but scripted getters would need a similar mechanism.
// see IonBuilder::getPropTryInnerize. This is fine for native/scripted getters
// because IsCacheableGetPropCallNative and IsCacheableGetPropCallScripted
// handle this.
if (cache.allowGetters() &&
(IsCacheableGetPropCallNative(obj, holder, shape) ||
IsCacheableGetPropCallPropertyOp(obj, holder, shape)))
IsCacheableGetPropCallPropertyOp(obj, holder, shape) ||
IsCacheableGetPropCallScripted(obj, holder, shape)))
{
// Don't enable getter call if cache is idempotent, since they can be
// effectful. This is handled by allowGetters()
@ -1995,6 +2059,19 @@ IsCacheableSetPropCallNative(HandleObject obj, HandleObject holder, HandleShape
shape->setterObject()->as<JSFunction>().isNative();
}
static bool
IsCacheableSetPropCallScripted(HandleObject obj, HandleObject holder, HandleShape shape)
{
MOZ_ASSERT(obj->isNative());
if (!shape || !IsCacheableProtoChainForIon(obj, holder))
return false;
return shape->hasSetterValue() && shape->setterObject() &&
shape->setterObject()->is<JSFunction>() &&
shape->setterObject()->as<JSFunction>().hasJITCode();
}
static bool
IsCacheableSetPropCallPropertyOp(HandleObject obj, HandleObject holder, HandleShape shape)
{
@ -2238,14 +2315,12 @@ GenerateCallSetter(JSContext *cx, IonScript *ion, MacroAssembler &masm,
//
// Be very careful not to use any of these before value is pushed, since they
// might shadow.
Register scratchReg = regSet.takeGeneral();
Register argJSContextReg = regSet.takeGeneral();
Register argVpReg = regSet.takeGeneral();
Register scratchReg = regSet.takeGeneral();
bool callNative = IsCacheableSetPropCallNative(obj, holder, shape);
MOZ_ASSERT_IF(!callNative, IsCacheableSetPropCallPropertyOp(obj, holder, shape));
if (IsCacheableSetPropCallNative(obj, holder, shape)) {
Register argJSContextReg = regSet.takeGeneral();
Register argVpReg = regSet.takeGeneral();
if (callNative) {
MOZ_ASSERT(shape->hasSetterValue() && shape->setterObject() &&
shape->setterObject()->is<JSFunction>());
JSFunction *target = &shape->setterObject()->as<JSFunction>();
@ -2290,7 +2365,9 @@ GenerateCallSetter(JSContext *cx, IonScript *ion, MacroAssembler &masm,
// masm.leaveExitFrame & pop locals.
masm.adjustStack(IonOOLNativeExitFrameLayout::Size(1));
} else {
} else if (IsCacheableSetPropCallPropertyOp(obj, holder, shape)) {
Register argJSContextReg = regSet.takeGeneral();
Register argVpReg = regSet.takeGeneral();
Register argObjReg = regSet.takeGeneral();
Register argIdReg = regSet.takeGeneral();
Register argStrictReg = regSet.takeGeneral();
@ -2338,6 +2415,52 @@ GenerateCallSetter(JSContext *cx, IonScript *ion, MacroAssembler &masm,
// masm.leaveExitFrame & pop locals.
masm.adjustStack(IonOOLPropertyOpExitFrameLayout::Size());
} else {
MOZ_ASSERT(IsCacheableSetPropCallScripted(obj, holder, shape));
JSFunction *target = &shape->setterValue().toObject().as<JSFunction>();
uint32_t framePushedBefore = masm.framePushed();
// Construct IonAccessorICFrameLayout.
uint32_t descriptor = MakeFrameDescriptor(masm.framePushed(), JitFrame_IonJS);
attacher.pushStubCodePointer(masm);
masm.Push(Imm32(descriptor));
masm.Push(ImmPtr(returnAddr));
// The JitFrameLayout pushed below will be aligned to JitStackAlignment,
// so we just have to make sure the stack is aligned after we push the
// |this| + argument Values.
uint32_t numArgs = Max(size_t(1), target->nargs());
uint32_t argSize = (numArgs + 1) * sizeof(Value);
uint32_t padding = ComputeByteAlignment(masm.framePushed() + argSize, JitStackAlignment);
MOZ_ASSERT(padding % sizeof(uintptr_t) == 0);
MOZ_ASSERT(padding < JitStackAlignment);
masm.reserveStack(padding);
for (size_t i = 1; i < target->nargs(); i++)
masm.Push(UndefinedValue());
masm.Push(value);
masm.Push(TypedOrValueRegister(MIRType_Object, AnyRegister(object)));
masm.movePtr(ImmMaybeNurseryPtr(target), scratchReg);
descriptor = MakeFrameDescriptor(argSize + padding, JitFrame_IonAccessorIC);
masm.Push(Imm32(1)); // argc
masm.Push(scratchReg);
masm.Push(Imm32(descriptor));
// Check stack alignment. Add sizeof(uintptr_t) for the return address.
MOZ_ASSERT(((masm.framePushed() + sizeof(uintptr_t)) % JitStackAlignment) == 0);
// The setter has JIT code now and we will only discard the setter's JIT
// code when discarding all JIT code in the Zone, so we can assume it'll
// still have JIT code.
MOZ_ASSERT(target->hasJITCode());
masm.loadPtr(Address(scratchReg, JSFunction::offsetOfNativeOrScript()), scratchReg);
masm.loadBaselineOrIonRaw(scratchReg, scratchReg, nullptr);
masm.callJit(scratchReg);
masm.freeStack(masm.framePushed() - framePushedBefore);
}
masm.icRestoreLive(liveRegs, aic);
@ -2364,7 +2487,8 @@ IsCacheableDOMProxyUnshadowedSetterCall(JSContext *cx, HandleObject obj, HandleP
return true;
if (!IsCacheableSetPropCallNative(checkObj, holder, shape) &&
!IsCacheableSetPropCallPropertyOp(checkObj, holder, shape))
!IsCacheableSetPropCallPropertyOp(checkObj, holder, shape) &&
!IsCacheableSetPropCallScripted(checkObj, holder, shape))
{
return true;
}
@ -2729,7 +2853,8 @@ CanAttachNativeSetProp(JSContext *cx, HandleObject obj, HandleId id, ConstantOrR
return SetPropertyIC::MaybeCanAttachAddSlot;
if (IsCacheableSetPropCallPropertyOp(obj, holder, shape) ||
IsCacheableSetPropCallNative(obj, holder, shape))
IsCacheableSetPropCallNative(obj, holder, shape) ||
IsCacheableSetPropCallScripted(obj, holder, shape))
{
return SetPropertyIC::CanAttachCallSetter;
}
@ -4095,7 +4220,8 @@ IsCacheableNameCallGetter(HandleObject scopeChain, HandleObject obj, HandleObjec
return false;
return IsCacheableGetPropCallNative(obj, holder, shape) ||
IsCacheableGetPropCallPropertyOp(obj, holder, shape);
IsCacheableGetPropCallPropertyOp(obj, holder, shape) ||
IsCacheableGetPropCallScripted(obj, holder, shape);
}
bool

View File

@ -44,18 +44,17 @@ enum FrameType
// mismatches in calls.
JitFrame_Rectifier,
// Ion IC calling a scripted getter/setter.
JitFrame_IonAccessorIC,
// An unwound JS frame is a JS frame signalling that its callee frame has been
// turned into an exit frame (see EnsureExitFrame). Used by Ion bailouts and
// Baseline exception unwinding.
JitFrame_Unwound_BaselineJS,
JitFrame_Unwound_IonJS,
// Like Unwound_IonJS, but the caller is a baseline stub frame.
JitFrame_Unwound_BaselineStub,
// An unwound rectifier frame is a rectifier frame signalling that its callee
// frame has been turned into an exit frame (see EnsureExitFrame).
JitFrame_Unwound_Rectifier,
JitFrame_Unwound_IonAccessorIC,
// An exit frame is necessary for transitioning from a JS frame into C++.
// From within C++, an exit frame is always the last frame in any

View File

@ -249,6 +249,7 @@ SizeOfFramePrefix(FrameType type)
case JitFrame_Unwound_IonJS:
return JitFrameLayout::Size();
case JitFrame_BaselineStub:
case JitFrame_Unwound_BaselineStub:
return BaselineStubFrameLayout::Size();
case JitFrame_Rectifier:
return RectifierFrameLayout::Size();
@ -256,9 +257,12 @@ SizeOfFramePrefix(FrameType type)
return IonUnwoundRectifierFrameLayout::Size();
case JitFrame_Exit:
return ExitFrameLayout::Size();
default:
MOZ_CRASH("unknown frame type");
case JitFrame_IonAccessorIC:
case JitFrame_Unwound_IonAccessorIC:
return IonAccessorICFrameLayout::Size();
}
MOZ_CRASH("unknown frame type");
}
uint8_t *
@ -302,6 +306,8 @@ JitFrameIterator::operator++()
type_ = JitFrame_BaselineJS;
else if (type_ == JitFrame_Unwound_BaselineStub)
type_ = JitFrame_BaselineStub;
else if (type_ == JitFrame_Unwound_IonAccessorIC)
type_ = JitFrame_IonAccessorIC;
returnAddressToFp_ = current()->returnAddress();
current_ = prev;
@ -889,43 +895,51 @@ HandleException(ResumeFromException *rfe)
void
EnsureExitFrame(CommonFrameLayout *frame)
{
if (frame->prevType() == JitFrame_Unwound_IonJS ||
frame->prevType() == JitFrame_Unwound_BaselineJS ||
frame->prevType() == JitFrame_Unwound_BaselineStub ||
frame->prevType() == JitFrame_Unwound_Rectifier)
{
switch (frame->prevType()) {
case JitFrame_Unwound_IonJS:
case JitFrame_Unwound_BaselineJS:
case JitFrame_Unwound_BaselineStub:
case JitFrame_Unwound_Rectifier:
case JitFrame_Unwound_IonAccessorIC:
// Already an exit frame, nothing to do.
return;
}
if (frame->prevType() == JitFrame_Entry) {
case JitFrame_Entry:
// The previous frame type is the entry frame, so there's no actual
// need for an exit frame.
return;
}
if (frame->prevType() == JitFrame_Rectifier) {
case JitFrame_Rectifier:
// The rectifier code uses the frame descriptor to discard its stack,
// so modifying its descriptor size here would be dangerous. Instead,
// we change the frame type, and teach the stack walking code how to
// deal with this edge case. bug 717297 would obviate the need
frame->changePrevType(JitFrame_Unwound_Rectifier);
return;
}
if (frame->prevType() == JitFrame_BaselineStub) {
case JitFrame_BaselineStub:
frame->changePrevType(JitFrame_Unwound_BaselineStub);
return;
}
if (frame->prevType() == JitFrame_BaselineJS) {
case JitFrame_BaselineJS:
frame->changePrevType(JitFrame_Unwound_BaselineJS);
return;
case JitFrame_IonJS:
frame->changePrevType(JitFrame_Unwound_IonJS);
return;
case JitFrame_IonAccessorIC:
frame->changePrevType(JitFrame_Unwound_IonAccessorIC);
return;
case JitFrame_Exit:
case JitFrame_Bailout:
// Fall-through to MOZ_CRASH below.
break;
}
MOZ_ASSERT(frame->prevType() == JitFrame_IonJS);
frame->changePrevType(JitFrame_Unwound_IonJS);
MOZ_CRASH("Unexpected frame type");
}
CalleeToken
@ -1169,6 +1183,14 @@ MarkBaselineStubFrame(JSTracer *trc, const JitFrameIterator &frame)
}
}
static void
MarkIonAccessorICFrame(JSTracer *trc, const JitFrameIterator &frame)
{
MOZ_ASSERT(frame.type() == JitFrame_IonAccessorIC);
IonAccessorICFrameLayout *layout = (IonAccessorICFrameLayout *)frame.fp();
gc::MarkJitCodeRoot(trc, layout->stubCode(), "ion-ic-accessor-code");
}
void
JitActivationIterator::jitStackRange(uintptr_t *&min, uintptr_t *&end)
{
@ -1441,12 +1463,17 @@ MarkJitActivation(JSTracer *trc, const JitActivationIterator &activations)
break;
case JitFrame_Unwound_IonJS:
case JitFrame_Unwound_BaselineJS:
case JitFrame_Unwound_BaselineStub:
case JitFrame_Unwound_IonAccessorIC:
MOZ_CRASH("invalid");
case JitFrame_Rectifier:
MarkRectifierFrame(trc, frames);
break;
case JitFrame_Unwound_Rectifier:
break;
case JitFrame_IonAccessorIC:
MarkIonAccessorICFrame(trc, frames);
break;
default:
MOZ_CRASH("unexpected frame type");
}
@ -2660,6 +2687,11 @@ JitFrameIterator::dump() const
fprintf(stderr, " Rectifier frame\n");
fprintf(stderr, " Frame size: %u\n", unsigned(current()->prevFrameLocalSize()));
break;
case JitFrame_IonAccessorIC:
case JitFrame_Unwound_IonAccessorIC:
fprintf(stderr, " Ion scripted accessor IC\n");
fprintf(stderr, " Frame size: %u\n", unsigned(current()->prevFrameLocalSize()));
break;
case JitFrame_Unwound_IonJS:
case JitFrame_Unwound_BaselineJS:
fprintf(stderr, "Warning! Unwound JS frames are not observable.\n");
@ -3012,6 +3044,18 @@ JitProfilingFrameIterator::operator++()
MOZ_CRASH("Bad frame type prior to rectifier frame.");
}
if (prevType == JitFrame_IonAccessorIC || prevType == JitFrame_Unwound_IonAccessorIC) {
IonAccessorICFrameLayout *accessorFrame =
GetPreviousRawFrame<JitFrameLayout, IonAccessorICFrameLayout *>(frame);
MOZ_ASSERT(accessorFrame->prevType() == JitFrame_IonJS);
returnAddressToFp_ = accessorFrame->returnAddress();
fp_ = GetPreviousRawFrame<IonAccessorICFrameLayout, uint8_t *>(accessorFrame);
type_ = JitFrame_IonJS;
return;
}
if (prevType == JitFrame_Entry) {
// No previous frame, set to null to indicate that JitFrameIterator is done()
returnAddressToFp_ = nullptr;

View File

@ -428,6 +428,21 @@ class RectifierFrameLayout : public JitFrameLayout
}
};
class IonAccessorICFrameLayout : public CommonFrameLayout
{
protected:
// Pointer to root the stub's JitCode.
JitCode *stubCode_;
public:
JitCode **stubCode() {
return &stubCode_;
}
static size_t Size() {
return sizeof(IonAccessorICFrameLayout);
}
};
// The callee token is now dead.
class IonUnwoundRectifierFrameLayout : public RectifierFrameLayout
{

View File

@ -1130,6 +1130,7 @@ JitRuntime::generateProfilerExitFrameTailStub(JSContext *cx)
Label handle_IonJS;
Label handle_BaselineStub;
Label handle_Rectifier;
Label handle_IonAccessorIC;
Label handle_Entry;
Label end;
@ -1137,6 +1138,7 @@ JitRuntime::generateProfilerExitFrameTailStub(JSContext *cx)
masm.branch32(Assembler::Equal, scratch2, Imm32(JitFrame_BaselineJS), &handle_IonJS);
masm.branch32(Assembler::Equal, scratch2, Imm32(JitFrame_BaselineStub), &handle_BaselineStub);
masm.branch32(Assembler::Equal, scratch2, Imm32(JitFrame_Rectifier), &handle_Rectifier);
masm.branch32(Assembler::Equal, scratch2, Imm32(JitFrame_IonAccessorIC), &handle_IonAccessorIC);
masm.branch32(Assembler::Equal, scratch2, Imm32(JitFrame_Entry), &handle_Entry);
masm.assumeUnreachable("Invalid caller frame type when exiting from Ion frame.");
@ -1307,6 +1309,54 @@ JitRuntime::generateProfilerExitFrameTailStub(JSContext *cx)
masm.ret();
}
// JitFrame_IonAccessorIC
//
// The caller is always an IonJS frame.
//
// Ion-Descriptor
// Ion-ReturnAddr
// ... ion frame data ... |- AccFrame-Descriptor.Size
// StubCode |
// AccFrame-Descriptor |- IonAccessorICFrameLayout::Size()
// AccFrame-ReturnAddr |
// ... accessor frame data & args ... |- Descriptor.Size
// ActualArgc |
// CalleeToken |- JitFrameLayout::Size()
// Descriptor |
// FP -----> ReturnAddr |
masm.bind(&handle_IonAccessorIC);
{
// scratch2 := StackPointer + Descriptor.size + JitFrameLayout::Size()
masm.ma_add(StackPointer, scratch1, scratch2);
masm.addPtr(Imm32(JitFrameLayout::Size()), scratch2);
// scratch3 := AccFrame-Descriptor.Size
masm.loadPtr(Address(scratch2, IonAccessorICFrameLayout::offsetOfDescriptor()), scratch3);
#ifdef DEBUG
// Assert previous frame is an IonJS frame.
masm.movePtr(scratch3, scratch1);
masm.and32(Imm32((1 << FRAMETYPE_BITS) - 1), scratch1);
{
Label checkOk;
masm.branch32(Assembler::Equal, scratch1, Imm32(JitFrame_IonJS), &checkOk);
masm.assumeUnreachable("IonAccessorIC frame must be preceded by IonJS frame");
masm.bind(&checkOk);
}
#endif
masm.rshiftPtr(Imm32(FRAMESIZE_SHIFT), scratch3);
// lastProfilingCallSite := AccFrame-ReturnAddr
masm.loadPtr(Address(scratch2, IonAccessorICFrameLayout::offsetOfReturnAddress()), scratch1);
masm.storePtr(scratch1, lastProfilingCallSite);
// lastProfilingFrame := AccessorFrame + AccFrame-Descriptor.Size +
// IonAccessorICFrameLayout::Size()
masm.ma_add(scratch2, scratch3, scratch1);
masm.addPtr(Imm32(IonAccessorICFrameLayout::Size()), scratch1);
masm.storePtr(scratch1, lastProfilingFrame);
masm.ret();
}
//
// JitFrame_Entry
//

View File

@ -1125,6 +1125,7 @@ JitRuntime::generateProfilerExitFrameTailStub(JSContext *cx)
Label handle_IonJS;
Label handle_BaselineStub;
Label handle_Rectifier;
Label handle_IonAccessorIC;
Label handle_Entry;
Label end;
@ -1132,6 +1133,7 @@ JitRuntime::generateProfilerExitFrameTailStub(JSContext *cx)
masm.branch32(Assembler::Equal, scratch2, Imm32(JitFrame_BaselineJS), &handle_IonJS);
masm.branch32(Assembler::Equal, scratch2, Imm32(JitFrame_BaselineStub), &handle_BaselineStub);
masm.branch32(Assembler::Equal, scratch2, Imm32(JitFrame_Rectifier), &handle_Rectifier);
masm.branch32(Assembler::Equal, scratch2, Imm32(JitFrame_IonAccessorIC), &handle_IonAccessorIC);
masm.branch32(Assembler::Equal, scratch2, Imm32(JitFrame_Entry), &handle_Entry);
masm.assumeUnreachable("Invalid caller frame type when exiting from Ion frame.");
@ -1302,6 +1304,54 @@ JitRuntime::generateProfilerExitFrameTailStub(JSContext *cx)
masm.ret();
}
// JitFrame_IonAccessorIC
//
// The caller is always an IonJS frame.
//
// Ion-Descriptor
// Ion-ReturnAddr
// ... ion frame data ... |- AccFrame-Descriptor.Size
// StubCode |
// AccFrame-Descriptor |- IonAccessorICFrameLayout::Size()
// AccFrame-ReturnAddr |
// ... accessor frame data & args ... |- Descriptor.Size
// ActualArgc |
// CalleeToken |- JitFrameLayout::Size()
// Descriptor |
// FP -----> ReturnAddr |
masm.bind(&handle_IonAccessorIC);
{
// scratch2 := StackPointer + Descriptor.size + JitFrameLayout::Size()
masm.ma_addu(StackPointer, scratch1, scratch2);
masm.addPtr(Imm32(JitFrameLayout::Size()), scratch2);
// scratch3 := AccFrame-Descriptor.Size
masm.loadPtr(Address(scratch2, IonAccessorICFrameLayout::offsetOfDescriptor()), scratch3);
#ifdef DEBUG
// Assert previous frame is an IonJS frame.
masm.movePtr(scratch3, scratch1);
masm.and32(Imm32((1 << FRAMETYPE_BITS) - 1), scratch1);
{
Label checkOk;
masm.branch32(Assembler::Equal, scratch1, Imm32(JitFrame_IonJS), &checkOk);
masm.assumeUnreachable("IonAccessorIC frame must be preceded by IonJS frame");
masm.bind(&checkOk);
}
#endif
masm.rshiftPtr(Imm32(FRAMESIZE_SHIFT), scratch3);
// lastProfilingCallSite := AccFrame-ReturnAddr
masm.loadPtr(Address(scratch2, IonAccessorICFrameLayout::offsetOfReturnAddress()), scratch1);
masm.storePtr(scratch1, lastProfilingCallSite);
// lastProfilingFrame := AccessorFrame + AccFrame-Descriptor.Size +
// IonAccessorICFrameLayout::Size()
masm.ma_addu(scratch2, scratch3, scratch1);
masm.addPtr(Imm32(IonAccessorICFrameLayout::Size()), scratch1);
masm.storePtr(scratch1, lastProfilingFrame);
masm.ret();
}
//
// JitFrame_Entry
//

View File

@ -981,6 +981,7 @@ JitRuntime::generateProfilerExitFrameTailStub(JSContext *cx)
Label handle_IonJS;
Label handle_BaselineStub;
Label handle_Rectifier;
Label handle_IonAccessorIC;
Label handle_Entry;
Label end;
@ -988,6 +989,7 @@ JitRuntime::generateProfilerExitFrameTailStub(JSContext *cx)
masm.branch32(Assembler::Equal, scratch2, Imm32(JitFrame_BaselineJS), &handle_IonJS);
masm.branch32(Assembler::Equal, scratch2, Imm32(JitFrame_BaselineStub), &handle_BaselineStub);
masm.branch32(Assembler::Equal, scratch2, Imm32(JitFrame_Rectifier), &handle_Rectifier);
masm.branch32(Assembler::Equal, scratch2, Imm32(JitFrame_IonAccessorIC), &handle_IonAccessorIC);
masm.branch32(Assembler::Equal, scratch2, Imm32(JitFrame_Entry), &handle_Entry);
masm.assumeUnreachable("Invalid caller frame type when exiting from Ion frame.");
@ -1153,6 +1155,52 @@ JitRuntime::generateProfilerExitFrameTailStub(JSContext *cx)
masm.ret();
}
// JitFrame_IonAccessorIC
//
// The caller is always an IonJS frame.
//
// Ion-Descriptor
// Ion-ReturnAddr
// ... ion frame data ... |- AccFrame-Descriptor.Size
// StubCode |
// AccFrame-Descriptor |- IonAccessorICFrameLayout::Size()
// AccFrame-ReturnAddr |
// ... accessor frame data & args ... |- Descriptor.Size
// ActualArgc |
// CalleeToken |- JitFrameLayout::Size()
// Descriptor |
// FP -----> ReturnAddr |
masm.bind(&handle_IonAccessorIC);
{
// scratch2 := StackPointer + Descriptor.size + JitFrameLayout::Size()
masm.lea(Operand(StackPointer, scratch1, TimesOne, JitFrameLayout::Size()), scratch2);
// scratch3 := AccFrame-Descriptor.Size
masm.loadPtr(Address(scratch2, IonAccessorICFrameLayout::offsetOfDescriptor()), scratch3);
#ifdef DEBUG
// Assert previous frame is an IonJS frame.
masm.movePtr(scratch3, scratch1);
masm.and32(Imm32((1 << FRAMETYPE_BITS) - 1), scratch1);
{
Label checkOk;
masm.branch32(Assembler::Equal, scratch1, Imm32(JitFrame_IonJS), &checkOk);
masm.assumeUnreachable("IonAccessorIC frame must be preceded by IonJS frame");
masm.bind(&checkOk);
}
#endif
masm.rshiftPtr(Imm32(FRAMESIZE_SHIFT), scratch3);
// lastProfilingCallSite := AccFrame-ReturnAddr
masm.loadPtr(Address(scratch2, IonAccessorICFrameLayout::offsetOfReturnAddress()), scratch1);
masm.storePtr(scratch1, lastProfilingCallSite);
// lastProfilingFrame := AccessorFrame + AccFrame-Descriptor.Size +
// IonAccessorICFrameLayout::Size()
masm.lea(Operand(scratch2, scratch3, TimesOne, IonAccessorICFrameLayout::Size()), scratch1);
masm.storePtr(scratch1, lastProfilingFrame);
masm.ret();
}
//
// JitFrame_Entry
//

View File

@ -1008,6 +1008,7 @@ JitRuntime::generateProfilerExitFrameTailStub(JSContext *cx)
Label handle_IonJS;
Label handle_BaselineStub;
Label handle_Rectifier;
Label handle_IonAccessorIC;
Label handle_Entry;
Label end;
@ -1015,6 +1016,7 @@ JitRuntime::generateProfilerExitFrameTailStub(JSContext *cx)
masm.branch32(Assembler::Equal, scratch2, Imm32(JitFrame_BaselineJS), &handle_IonJS);
masm.branch32(Assembler::Equal, scratch2, Imm32(JitFrame_BaselineStub), &handle_BaselineStub);
masm.branch32(Assembler::Equal, scratch2, Imm32(JitFrame_Rectifier), &handle_Rectifier);
masm.branch32(Assembler::Equal, scratch2, Imm32(JitFrame_IonAccessorIC), &handle_IonAccessorIC);
masm.branch32(Assembler::Equal, scratch2, Imm32(JitFrame_Entry), &handle_Entry);
masm.assumeUnreachable("Invalid caller frame type when exiting from Ion frame.");
@ -1182,6 +1184,52 @@ JitRuntime::generateProfilerExitFrameTailStub(JSContext *cx)
masm.ret();
}
// JitFrame_IonAccessorIC
//
// The caller is always an IonJS frame.
//
// Ion-Descriptor
// Ion-ReturnAddr
// ... ion frame data ... |- AccFrame-Descriptor.Size
// StubCode |
// AccFrame-Descriptor |- IonAccessorICFrameLayout::Size()
// AccFrame-ReturnAddr |
// ... accessor frame data & args ... |- Descriptor.Size
// ActualArgc |
// CalleeToken |- JitFrameLayout::Size()
// Descriptor |
// FP -----> ReturnAddr |
masm.bind(&handle_IonAccessorIC);
{
// scratch2 := StackPointer + Descriptor.size + JitFrameLayout::Size()
masm.lea(Operand(StackPointer, scratch1, TimesOne, JitFrameLayout::Size()), scratch2);
// scratch3 := AccFrame-Descriptor.Size
masm.loadPtr(Address(scratch2, IonAccessorICFrameLayout::offsetOfDescriptor()), scratch3);
#ifdef DEBUG
// Assert previous frame is an IonJS frame.
masm.movePtr(scratch3, scratch1);
masm.and32(Imm32((1 << FRAMETYPE_BITS) - 1), scratch1);
{
Label checkOk;
masm.branch32(Assembler::Equal, scratch1, Imm32(JitFrame_IonJS), &checkOk);
masm.assumeUnreachable("IonAccessorIC frame must be preceded by IonJS frame");
masm.bind(&checkOk);
}
#endif
masm.rshiftPtr(Imm32(FRAMESIZE_SHIFT), scratch3);
// lastProfilingCallSite := AccFrame-ReturnAddr
masm.loadPtr(Address(scratch2, IonAccessorICFrameLayout::offsetOfReturnAddress()), scratch1);
masm.storePtr(scratch1, lastProfilingCallSite);
// lastProfilingFrame := AccessorFrame + AccFrame-Descriptor.Size +
// IonAccessorICFrameLayout::Size()
masm.lea(Operand(scratch2, scratch3, TimesOne, IonAccessorICFrameLayout::Size()), scratch1);
masm.storePtr(scratch1, lastProfilingFrame);
masm.ret();
}
//
// JitFrame_Entry
//

View File

@ -2968,9 +2968,9 @@ GCRuntime::refillFreeListFromMainThread(JSContext *cx, AllocKind thingKind)
if (!allowGC)
return nullptr;
JS::PrepareZoneForGC(cx->zone());
JS::PrepareForFullGC(rt);
AutoKeepAtoms keepAtoms(cx->perThreadData);
rt->gc.gc(GC_NORMAL, JS::gcreason::LAST_DITCH);
rt->gc.gc(GC_SHRINK, JS::gcreason::LAST_DITCH);
}
// Retry the allocation after the last-ditch GC.

View File

@ -0,0 +1,21 @@
if (typeof window === "undefined") {
// This test is meant to run in the browser, but it's easy to
// run it in the shell as well, even though it has no inner/outer
// windows.
window = this;
}
var res = false;
Object.defineProperty(this, "foo", {configurable: true,
get: function() { return this === window; },
set: function(v) { res = this === window; }});
(function() {
for (var i = 0; i < 3000; ++i) {
window.foo = i;
assertEq(res, true, "setter");
assertEq(window.foo, true, "getter");
}
})();
reportCompare(true, true);

View File

@ -2171,13 +2171,14 @@ TemporaryTypeSet::maybeEmulatesUndefined(CompilerConstraintList *constraints)
return false;
}
JSObject *
TemporaryTypeSet::getCommonPrototype(CompilerConstraintList *constraints)
bool
TemporaryTypeSet::getCommonPrototype(CompilerConstraintList *constraints, JSObject **proto)
{
if (unknownObject())
return nullptr;
return false;
JSObject *proto = nullptr;
*proto = nullptr;
bool isFirst = true;
unsigned count = getObjectCount();
for (unsigned i = 0; i < count; i++) {
@ -2186,27 +2187,27 @@ TemporaryTypeSet::getCommonPrototype(CompilerConstraintList *constraints)
continue;
if (key->unknownProperties())
return nullptr;
return false;
TaggedProto nproto = key->proto();
if (proto) {
if (nproto != TaggedProto(proto))
return nullptr;
if (isFirst) {
if (nproto.isLazy())
return false;
*proto = nproto.toObjectOrNull();
isFirst = false;
} else {
if (!nproto.isObject())
return nullptr;
proto = nproto.toObject();
if (nproto != TaggedProto(*proto))
return false;
}
}
// Guard against mutating __proto__.
for (unsigned i = 0; i < count; i++) {
ObjectKey *key = getObject(i);
if (key)
if (ObjectKey *key = getObject(i))
JS_ALWAYS_TRUE(key->hasStableClassAndProto(constraints));
}
return proto;
return true;
}
bool
@ -2281,10 +2282,13 @@ js::TypeCanHaveExtraIndexedProperties(CompilerConstraintList *constraints,
if (types->hasObjectFlags(constraints, OBJECT_FLAG_SPARSE_INDEXES))
return true;
JSObject *proto = types->getCommonPrototype(constraints);
if (!proto)
JSObject *proto;
if (!types->getCommonPrototype(constraints, &proto))
return true;
if (!proto)
return false;
return PrototypeHasIndexedProperty(constraints, proto);
}

View File

@ -671,8 +671,11 @@ class TemporaryTypeSet : public TypeSet
ForAllResult forAllClasses(CompilerConstraintList *constraints,
bool (*func)(const Class *clasp));
/* Get the prototype shared by all objects in this set, or nullptr. */
JSObject *getCommonPrototype(CompilerConstraintList *constraints);
/*
* Returns true if all objects in this set have the same prototype, and
* assigns this object to *proto. The proto can be nullptr.
*/
bool getCommonPrototype(CompilerConstraintList *constraints, JSObject **proto);
/* Get the typed array type of all objects in this set, or Scalar::MaxTypedArrayViewType. */
Scalar::Type getTypedArrayType(CompilerConstraintList *constraints);

View File

@ -1222,11 +1222,11 @@ nsBidiPresUtils::ResolveParagraphWithinBlock(nsBlockFrame* aBlockFrame,
}
void
nsBidiPresUtils::ReorderFrames(nsIFrame* aFirstFrameOnLine,
int32_t aNumFramesOnLine,
WritingMode aLineWM,
nscoord aLineWidth,
nscoord aStart)
nsBidiPresUtils::ReorderFrames(nsIFrame* aFirstFrameOnLine,
int32_t aNumFramesOnLine,
WritingMode aLineWM,
const nsSize& aContainerSize,
nscoord aStart)
{
// If this line consists of a line frame, reorder the line frame's children.
if (aFirstFrameOnLine->GetType() == nsGkAtoms::lineFrame) {
@ -1239,7 +1239,8 @@ nsBidiPresUtils::ReorderFrames(nsIFrame* aFirstFrameOnLine,
}
BidiLineData bld(aFirstFrameOnLine, aNumFramesOnLine);
RepositionInlineFrames(&bld, aFirstFrameOnLine, aLineWM, aLineWidth, aStart);
RepositionInlineFrames(&bld, aFirstFrameOnLine, aLineWM,
aContainerSize, aStart);
}
nsIFrame*
@ -1400,7 +1401,7 @@ nsBidiPresUtils::RepositionFrame(nsIFrame* aFrame,
nscoord& aStart,
nsContinuationStates* aContinuationStates,
WritingMode aContainerWM,
nscoord aContainerWidth)
const nsSize& aContainerSize)
{
if (!aFrame)
return;
@ -1465,7 +1466,7 @@ nsBidiPresUtils::RepositionFrame(nsIFrame* aFrame,
iCoord,
aContinuationStates,
frameWM,
aFrame->GetLogicalSize(aContainerWM).Width(aContainerWM));
aFrame->GetSize());
index++;
frame = reverseOrder ?
childList[childList.Length() - index - 1] :
@ -1477,11 +1478,22 @@ nsBidiPresUtils::RepositionFrame(nsIFrame* aFrame,
aStart += aFrame->ISize(aContainerWM);
}
LogicalRect logicalRect = aFrame->GetLogicalRect(aContainerWM,
aContainerWidth);
logicalRect.IStart(aContainerWM) = start;
logicalRect.ISize(aContainerWM) = aStart - start;
aFrame->SetRect(aContainerWM, logicalRect, aContainerWidth);
// LogicalRect doesn't correctly calculate the vertical position
// in vertical writing modes with right-to-left direction (Bug 1131451).
// This does the correct calculation ad hoc pending the fix for that.
nsRect rect = aFrame->GetRect();
nscoord lineSize = aContainerWM.IsVertical()
? aContainerSize.height : aContainerSize.width;
NS_ASSERTION(aContainerWM.IsBidiLTR() || lineSize != NS_UNCONSTRAINEDSIZE,
"Unconstrained inline line size in bidi frame reordering");
nscoord frameIStart = aContainerWM.IsBidiLTR() ? start : lineSize - aStart;
nscoord frameISize = aStart - start;
(aContainerWM.IsVertical() ? rect.y : rect.x) = frameIStart;
(aContainerWM.IsVertical() ? rect.height : rect.width) = frameISize;
aFrame->SetRect(rect);
aStart += margin.IEnd(aContainerWM);
}
@ -1510,7 +1522,7 @@ void
nsBidiPresUtils::RepositionInlineFrames(BidiLineData *aBld,
nsIFrame* aFirstChild,
WritingMode aLineWM,
nscoord aLineWidth,
const nsSize& aContainerSize,
nscoord aStart)
{
nscoord start = aStart;
@ -1543,7 +1555,7 @@ nsBidiPresUtils::RepositionInlineFrames(BidiLineData *aBld,
start,
&continuationStates,
aLineWM,
aLineWidth);
aContainerSize);
}
}

View File

@ -25,6 +25,7 @@ class nsPresContext;
class nsRenderingContext;
class nsBlockInFlowLineIterator;
class nsStyleContext;
struct nsSize;
template<class T> class nsTHashtable;
namespace mozilla { class WritingMode; }
@ -161,7 +162,7 @@ public:
static void ReorderFrames(nsIFrame* aFirstFrameOnLine,
int32_t aNumFramesOnLine,
mozilla::WritingMode aLineWM,
nscoord aLineWidth,
const nsSize& aContainerSize,
nscoord aStart);
/**
@ -430,7 +431,7 @@ private:
nscoord& aStart,
nsContinuationStates* aContinuationStates,
mozilla::WritingMode aContainerWM,
nscoord aContainerWidth);
const nsSize& aContainerSize);
/*
* Initialize the continuation state(nsFrameContinuationState) to
@ -483,7 +484,7 @@ private:
static void RepositionInlineFrames(BidiLineData* aBld,
nsIFrame* aFirstChild,
mozilla::WritingMode aLineWM,
nscoord aLineWidth,
const nsSize& aContainerSize,
nscoord aStart);
/**

View File

@ -5100,6 +5100,19 @@ nsLayoutUtils::GetSnappedBaselineY(nsIFrame* aFrame, gfxContext* aContext,
return aContext->DeviceToUser(putativeRect.TopLeft()).y * appUnitsPerDevUnit;
}
gfxFloat
nsLayoutUtils::GetSnappedBaselineX(nsIFrame* aFrame, gfxContext* aContext,
nscoord aX, nscoord aAscent)
{
gfxFloat appUnitsPerDevUnit = aFrame->PresContext()->AppUnitsPerDevPixel();
gfxFloat baseline = gfxFloat(aX) + aAscent;
gfxRect putativeRect(baseline / appUnitsPerDevUnit, 0, 1, 1);
if (!aContext->UserToDevicePixelSnapped(putativeRect, true)) {
return baseline;
}
return aContext->DeviceToUser(putativeRect.TopLeft()).x * appUnitsPerDevUnit;
}
// Hard limit substring lengths to 8000 characters ... this lets us statically
// size the cluster buffer array in FindSafeLength
#define MAX_GFX_TEXT_BUF_SIZE 8000

View File

@ -1477,6 +1477,10 @@ public:
// Get a baseline y position in app units that is snapped to device pixels.
static gfxFloat GetSnappedBaselineY(nsIFrame* aFrame, gfxContext* aContext,
nscoord aY, nscoord aAscent);
// Ditto for an x position (for vertical text). Note that for vertical-rl
// writing mode, the ascent value should be negated by the caller.
static gfxFloat GetSnappedBaselineX(nsIFrame* aFrame, gfxContext* aContext,
nscoord aX, nscoord aAscent);
static nscoord AppUnitWidthOfString(char16_t aC,
nsFontMetrics& aFontMetrics,

View File

@ -105,7 +105,7 @@ class SelectionCaretsTest(MarionetteTestCase):
self.actions.flick(el, caret2_x, caret2_y, end_caret_x, end_caret_y).perform()
# Move the left caret to the previous position of the right caret.
self.actions.flick(el, caret1_x, caret2_y, caret2_x, caret2_y).perform()
self.actions.flick(el, caret1_x, caret1_y, caret2_x, caret2_y).perform()
# Ignore extra spaces at the beginning of the content in comparison.
assertFunc(target_content.lstrip(), sel.selected_content.lstrip())
@ -140,7 +140,7 @@ class SelectionCaretsTest(MarionetteTestCase):
# Move the right caret to the position of the left caret.
(caret1_x, caret1_y), (caret2_x, caret2_y) = sel.selection_carets_location()
self.actions.flick(el, caret2_x, caret2_y, caret1_x, caret1_y,).perform()
self.actions.flick(el, caret2_x, caret2_y, caret1_x, caret1_y).perform()
assertFunc(target_content, sel.selected_content)
@ -162,6 +162,46 @@ class SelectionCaretsTest(MarionetteTestCase):
self._test_minimum_select_one_character(el2, self.assertEqual,
x=x, y=y)
def _test_handle_tilt_when_carets_overlap_to_each_other(self, el, assertFunc):
'''Test tilt handling when carets overlap to each other.
Let SelectionCarets overlap to each other. If SelectionCarets are set
to tilted successfully, tapping the tilted carets should not cause the
selection to be collapsed and the carets should be draggable.
'''
sel = SelectionManager(el)
original_content = sel.content
words = original_content.split()
self.assertTrue(len(words) >= 1, 'Expect at least one word in the content.')
# Goal: Select the first word.
x, y = self._first_word_location(el)
self._long_press_to_select(el, x, y)
target_content = sel.selected_content
# Move the left caret to the position of the right caret to trigger
# carets overlapping.
(caret1_x, caret1_y), (caret2_x, caret2_y) = sel.selection_carets_location()
self.actions.flick(el, caret1_x, caret1_y, caret2_x, caret2_y).perform()
# Caret width is 29px, so we make a series of hit tests for the two
# tilted carets. If any of the hits is missed, selection would be
# collapsed and both two carets should not be draggable.
(caret3_x, caret3_y), (caret4_x, caret4_y) = sel.selection_carets_location()
right_x = int(caret4_x + 0.5)
for i in range (right_x, right_x + 29, + 1):
self.actions.press(el, i, caret4_y).release().perform()
left_x = int(caret3_x - 0.5)
for i in range (left_x, left_x - 29, - 1):
self.actions.press(el, i, caret3_y).release().perform()
# Drag the left caret back to the initial selection, the first word.
self.actions.flick(el, caret3_x, caret3_y, caret1_x, caret1_y).perform()
assertFunc(target_content, sel.selected_content)
########################################################################
# <input> test cases with selection carets enabled
########################################################################
@ -173,7 +213,7 @@ class SelectionCaretsTest(MarionetteTestCase):
self.openTestHtml(enabled=True)
self._test_move_selection_carets(self._input, self.assertEqual)
def test_input_minimum_select_one_caracter(self):
def test_input_minimum_select_one_character(self):
self.openTestHtml(enabled=True)
self._test_minimum_select_one_character(self._input, self.assertEqual)
@ -189,6 +229,10 @@ class SelectionCaretsTest(MarionetteTestCase):
self.openTestHtml(enabled=True)
self._test_focus_obtained_by_long_press(self._content, self._input)
def test_input_handle_tilt_when_carets_overlap_to_each_other(self):
self.openTestHtml(enabled=True)
self._test_handle_tilt_when_carets_overlap_to_each_other(self._input, self.assertEqual)
########################################################################
# <input> test cases with selection carets disabled
########################################################################
@ -211,7 +255,7 @@ class SelectionCaretsTest(MarionetteTestCase):
self.openTestHtml(enabled=True)
self._test_move_selection_carets(self._textarea, self.assertEqual)
def test_textarea_minimum_select_one_caracter(self):
def test_textarea_minimum_select_one_character(self):
self.openTestHtml(enabled=True)
self._test_minimum_select_one_character(self._textarea, self.assertEqual)
@ -227,6 +271,10 @@ class SelectionCaretsTest(MarionetteTestCase):
self.openTestHtml(enabled=True)
self._test_focus_obtained_by_long_press(self._content, self._textarea)
def test_textarea_handle_tilt_when_carets_overlap_to_each_other(self):
self.openTestHtml(enabled=True)
self._test_handle_tilt_when_carets_overlap_to_each_other(self._textarea, self.assertEqual)
########################################################################
# <textarea> test cases with selection carets disabled
########################################################################
@ -249,7 +297,7 @@ class SelectionCaretsTest(MarionetteTestCase):
self.openTestHtml(enabled=True)
self._test_move_selection_carets(self._textarea_rtl, self.assertEqual)
def test_textarea_rtl_minimum_select_one_caracter(self):
def test_textarea_rtl_minimum_select_one_character(self):
self.openTestHtml(enabled=True)
self._test_minimum_select_one_character(self._textarea_rtl, self.assertEqual)
@ -291,6 +339,10 @@ class SelectionCaretsTest(MarionetteTestCase):
self.openTestHtml(enabled=True)
self._test_focus_obtained_by_long_press(self._content, self._contenteditable)
def test_contenteditable_handle_tilt_when_carets_overlap_to_each_other(self):
self.openTestHtml(enabled=True)
self._test_handle_tilt_when_carets_overlap_to_each_other(self._contenteditable, self.assertEqual)
########################################################################
# <div> contenteditable test cases with selection carets disabled
########################################################################
@ -321,6 +373,10 @@ class SelectionCaretsTest(MarionetteTestCase):
self.openTestHtml(enabled=True)
self._test_focus_obtained_by_long_press(self._contenteditable, self._content)
def test_content_non_editable_handle_tilt_when_carets_overlap_to_each_other(self):
self.openTestHtml(enabled=True)
self._test_handle_tilt_when_carets_overlap_to_each_other(self._content, self.assertEqual)
########################################################################
# <div> contenteditable2 test cases with selection carets enabled
########################################################################

View File

@ -433,9 +433,8 @@ nsFieldSetFrame::Reflow(nsPresContext* aPresContext,
"Bogus availSize.ISize; should be bigger");
// get our border and padding
nsMargin border = aReflowState.ComputedPhysicalBorderPadding() -
aReflowState.ComputedPhysicalPadding();
LogicalMargin logBorder(wm, border);
LogicalMargin border = aReflowState.ComputedLogicalBorderPadding() -
aReflowState.ComputedLogicalPadding();
// Figure out how big the legend is if there is one.
// get the legend's margin
@ -450,7 +449,7 @@ nsFieldSetFrame::Reflow(nsPresContext* aPresContext,
nsHTMLReflowMetrics legendDesiredSize(aReflowState);
ReflowChild(legend, aPresContext, legendDesiredSize, *legendReflowState,
0, 0, NS_FRAME_NO_MOVE_FRAME, aStatus);
wm, LogicalPoint(wm), 0, NS_FRAME_NO_MOVE_FRAME, aStatus);
#ifdef NOISY_REFLOW
printf(" returned (%d, %d)\n",
legendDesiredSize.Width(), legendDesiredSize.Height());
@ -463,12 +462,12 @@ nsFieldSetFrame::Reflow(nsPresContext* aPresContext,
legendDesiredSize.BSize(wm) + legendMargin.BStartEnd(wm));
nscoord oldSpace = mLegendSpace;
mLegendSpace = 0;
if (mLegendRect.BSize(wm) > logBorder.BStart(wm)) {
if (mLegendRect.BSize(wm) > border.BStart(wm)) {
// center the border on the legend
mLegendSpace = mLegendRect.BSize(wm) - logBorder.BStart(wm);
mLegendSpace = mLegendRect.BSize(wm) - border.BStart(wm);
} else {
mLegendRect.BStart(wm) =
(logBorder.BStart(wm) - mLegendRect.BSize(wm)) / 2;
(border.BStart(wm) - mLegendRect.BSize(wm)) / 2;
}
// if the legend space changes then we need to reflow the
@ -479,7 +478,8 @@ nsFieldSetFrame::Reflow(nsPresContext* aPresContext,
// We'll move the legend to its proper place later.
FinishReflowChild(legend, aPresContext, legendDesiredSize,
legendReflowState.ptr(), 0, 0, NS_FRAME_NO_MOVE_FRAME);
legendReflowState.ptr(), wm, LogicalPoint(wm), 0,
NS_FRAME_NO_MOVE_FRAME);
} else if (!legend) {
mLegendRect.SetEmpty();
mLegendSpace = 0;
@ -489,6 +489,8 @@ nsFieldSetFrame::Reflow(nsPresContext* aPresContext,
legendMargin = legend->GetLogicalUsedMargin(wm);
}
nscoord containerWidth = (wm.IsVertical() ? mLegendSpace : 0) +
border.LeftRight(wm);
// reflow the content frame only if needed
if (reflowInner) {
nsHTMLReflowState kidReflowState(aPresContext, aReflowState, inner,
@ -520,23 +522,21 @@ nsFieldSetFrame::Reflow(nsPresContext* aPresContext,
// Reflow the frame
NS_ASSERTION(kidReflowState.ComputedPhysicalMargin() == nsMargin(0,0,0,0),
"Margins on anonymous fieldset child not supported!");
nsPoint pt(border.left, border.top);
if (wm.IsVerticalLR()) {
pt.x += mLegendSpace;
} else if (!wm.IsVertical()) {
pt.y += mLegendSpace;
}
ReflowChild(inner, aPresContext, kidDesiredSize, kidReflowState,
pt.x, pt.y, 0, aStatus);
LogicalPoint pt(wm, border.IStart(wm), border.BStart(wm) + mLegendSpace);
ReflowChild(inner, aPresContext, kidDesiredSize, kidReflowState,
wm, pt, containerWidth, 0, aStatus);
// update the container width after reflowing the inner frame
FinishReflowChild(inner, aPresContext, kidDesiredSize,
&kidReflowState, pt.x, pt.y, 0);
&kidReflowState, wm, pt,
containerWidth + kidDesiredSize.Width(), 0);
NS_FRAME_TRACE_REFLOW_OUT("FieldSet::Reflow", aStatus);
}
nscoord containerWidth =
(wm.IsVertical() ? mLegendSpace : 0) +
logBorder.LeftRight(wm) + (inner ? inner->GetSize().width : 0);
if (inner) {
containerWidth += inner->GetSize().width;
}
LogicalRect contentRect(wm);
if (inner) {
@ -605,9 +605,9 @@ nsFieldSetFrame::Reflow(nsPresContext* aPresContext,
}
// Return our size and our result.
LogicalSize finalSize(wm, contentRect.ISize(wm) + logBorder.IStartEnd(wm),
mLegendSpace + logBorder.BStartEnd(wm) +
(inner ? inner->GetLogicalSize(wm).BSize(wm) : 0));
LogicalSize finalSize(wm, contentRect.ISize(wm) + border.IStartEnd(wm),
mLegendSpace + border.BStartEnd(wm) +
(inner ? inner->BSize(wm) : 0));
aDesiredSize.SetSize(wm, finalSize);
aDesiredSize.SetOverflowAreasToDesiredBounds();

View File

@ -1141,6 +1141,16 @@ nsBlockFrame::Reflow(nsPresContext* aPresContext,
PrepareResizeReflow(state);
}
// The same for percentage text-indent, except conditioned on the
// parent resizing.
if (!(GetStateBits() & NS_FRAME_IS_DIRTY) &&
reflowState->mCBReflowState &&
reflowState->mCBReflowState->IsIResize() &&
reflowState->mStyleText->mTextIndent.HasPercent() &&
!mLines.empty()) {
mLines.front()->MarkDirty();
}
LazyMarkLinesDirty();
mState &= ~NS_FRAME_FIRST_REFLOW;
@ -1262,7 +1272,7 @@ nsBlockFrame::Reflow(nsPresContext* aPresContext,
// physical origins.
if (wm.IsVerticalRL()) {
nscoord containerWidth = aMetrics.Width();
nscoord deltaX = containerWidth - state.mContainerWidth;
nscoord deltaX = containerWidth - state.ContainerWidth();
if (deltaX) {
for (line_iterator line = begin_lines(), end = end_lines();
line != end; line++) {
@ -1923,7 +1933,7 @@ nsBlockFrame::PropagateFloatDamage(nsBlockReflowState& aState,
// Scrollable overflow should be sufficient for things that affect
// layout.
WritingMode wm = aState.mReflowState.GetWritingMode();
nscoord containerWidth = aState.mContainerWidth;
nscoord containerWidth = aState.ContainerWidth();
LogicalRect overflow = aLine->GetOverflowArea(eScrollableOverflow, wm,
containerWidth);
nscoord lineBCoordCombinedBefore = overflow.BStart(wm) + aDeltaBCoord;
@ -2174,8 +2184,8 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState)
// If the container width has changed reset the container width. If the
// line's writing mode is not ltr, or if the line is not left-aligned, also
// mark the line dirty.
if (aState.mContainerWidth != line->mContainerWidth) {
line->mContainerWidth = aState.mContainerWidth;
if (aState.ContainerWidth() != line->mContainerWidth) {
line->mContainerWidth = aState.ContainerWidth();
bool isLastLine = line == mLines.back() &&
!GetNextInFlow() &&
@ -2812,7 +2822,7 @@ nsBlockFrame::SlideLine(nsBlockReflowState& aState,
NS_PRECONDITION(aDeltaBCoord != 0, "why slide a line nowhere?");
// Adjust line state
aLine->SlideBy(aDeltaBCoord, aState.mContainerWidth);
aLine->SlideBy(aDeltaBCoord, aState.ContainerWidth());
// Adjust the frames in the line
MoveChildFramesOfLine(aLine, aDeltaBCoord);
@ -3699,7 +3709,7 @@ nsBlockFrame::DoReflowInlineFrames(nsBlockReflowState& aState,
WritingMode lineWM = GetWritingMode(aLine->mFirstChild);
LogicalRect lineRect =
aFloatAvailableSpace.mRect.ConvertTo(lineWM, outerWM,
aState.mContainerWidth);
aState.ContainerWidth());
nscoord iStart = lineRect.IStart(lineWM);
nscoord availISize = lineRect.ISize(lineWM);
@ -3720,7 +3730,7 @@ nsBlockFrame::DoReflowInlineFrames(nsBlockReflowState& aState,
availISize, availBSize,
aFloatAvailableSpace.mHasFloats,
false, /*XXX isTopOfPage*/
lineWM, aState.mContainerWidth);
lineWM, aState.mContainerSize);
aState.SetFlag(BRS_LINE_LAYOUT_EMPTY, false);
@ -7045,7 +7055,7 @@ nsBlockFrame::ReflowBullet(nsIFrame* aBulletFrame,
aBulletFrame->SetRect(wm, LogicalRect(wm, iStart, bStart,
aMetrics.ISize(wm),
aMetrics.BSize(wm)),
aState.mContainerWidth);
aState.ContainerWidth());
aBulletFrame->DidReflow(aState.mPresContext, &aState.mReflowState,
nsDidReflowStatus::FINISHED);
}

View File

@ -228,7 +228,7 @@ nsBlockReflowContext::ReflowBlock(const LogicalRect& aSpace,
{
mFrame = aFrameRS.frame;
mWritingMode = aState.mReflowState.GetWritingMode();
mContainerWidth = aState.mContainerWidth;
mContainerWidth = aState.ContainerWidth();
mSpace = aSpace;
if (!aIsAdjacentWithBStart) {

View File

@ -65,19 +65,27 @@ nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
aFrame->GetLogicalSkipSides(&aReflowState);
mBorderPadding.ApplySkipSides(logicalSkipSides);
// Note that mContainerWidth is the physical width, needed to convert
// logical block-coordinates in vertical-rl writing mode (measured from a
// RHS origin) to physical coordinates within the containing block.
// If aReflowState doesn't have a constrained ComputedWidth(), we set it to
// zero, which means lines will be positioned (physically) incorrectly;
// we will fix them up at the end of nsBlockFrame::Reflow, after we know
// the total block-size of the frame.
mContainerWidth = aReflowState.ComputedWidth();
if (mContainerWidth == NS_UNCONSTRAINEDSIZE) {
mContainerWidth = 0;
// Note that mContainerSize is the physical size, needed to
// convert logical block-coordinates in vertical-rl writing mode
// (measured from a RHS origin) to physical coordinates within the
// containing block.
// If aReflowState doesn't have a constrained ComputedWidth(), we set
// mContainerSize.width to zero, which means lines will be positioned
// (physically) incorrectly; we will fix them up at the end of
// nsBlockFrame::Reflow, after we know the total block-size of the
// frame.
mContainerSize.width = aReflowState.ComputedWidth();
if (mContainerSize.width == NS_UNCONSTRAINEDSIZE) {
mContainerSize.width = 0;
}
mContainerWidth += mBorderPadding.LeftRight(wm);
mContainerSize.width += mBorderPadding.LeftRight(wm);
// For now at least, we don't do that fix-up for mContainerHeight.
// It's only used in nsBidiUtils::ReorderFrames for vertical rtl
// writing modes, which aren't fully supported for the time being.
mContainerSize.height = aReflowState.ComputedHeight() +
mBorderPadding.TopBottom(wm);
if ((aBStartMarginRoot && !logicalSkipSides.BStart()) ||
0 != mBorderPadding.BStart(wm)) {
@ -320,7 +328,7 @@ nsBlockReflowState::GetFloatAvailableSpaceWithState(
nsFlowAreaRect result =
mFloatManager->GetFlowArea(wm, aBCoord, nsFloatManager::BAND_FROM_POINT,
blockSize, mContentArea, aState,
mContainerWidth);
ContainerWidth());
// Keep the inline size >= 0 for compatibility with nsSpaceManager.
if (result.mRect.ISize(wm) < 0) {
result.mRect.ISize(wm) = 0;
@ -357,7 +365,7 @@ nsBlockReflowState::GetFloatAvailableSpaceForBSize(
#endif
nsFlowAreaRect result =
mFloatManager->GetFlowArea(wm, aBCoord, nsFloatManager::WIDTH_WITHIN_HEIGHT,
aBSize, mContentArea, aState, mContainerWidth);
aBSize, mContentArea, aState, ContainerWidth());
// Keep the width >= 0 for compatibility with nsSpaceManager.
if (result.mRect.ISize(wm) < 0) {
result.mRect.ISize(wm) = 0;
@ -488,7 +496,7 @@ nsBlockReflowState::RecoverFloats(nsLineList::iterator aLine,
mFloatManagerOrigin.B(mFloatManagerWM));
nsFrame::ListTag(stdout, floatFrame);
LogicalRect region = nsFloatManager::GetRegionFor(wm, floatFrame,
mContainerWidth);
ContainerWidth());
printf(" aDeltaBCoord=%d region={%d,%d,%d,%d}\n",
aDeltaBCoord, region.IStart(wm), region.BStart(wm),
region.ISize(wm), region.BSize(wm));
@ -496,13 +504,13 @@ nsBlockReflowState::RecoverFloats(nsLineList::iterator aLine,
#endif
mFloatManager->AddFloat(floatFrame,
nsFloatManager::GetRegionFor(wm, floatFrame,
mContainerWidth),
wm, mContainerWidth);
ContainerWidth()),
wm, ContainerWidth());
fc = fc->Next();
}
} else if (aLine->IsBlock()) {
nsBlockFrame::RecoverFloatsFor(aLine->mFirstChild, *mFloatManager, wm,
mContainerWidth);
ContainerWidth());
}
mFloatManager->Untranslate(oldWM, oPt);
}
@ -696,7 +704,7 @@ nsBlockReflowState::FlowAndPlaceFloat(nsIFrame* aFloat)
// The float's old region, so we can propagate damage.
LogicalRect oldRegion = nsFloatManager::GetRegionFor(wm, aFloat,
mContainerWidth);
ContainerWidth());
// Enforce CSS2 9.5.1 rule [2], i.e., make sure that a float isn't
// ``above'' another float that preceded it in the flow.
@ -704,7 +712,7 @@ nsBlockReflowState::FlowAndPlaceFloat(nsIFrame* aFloat)
// set the origin to our writing mode
LogicalPoint oPt(wm);
WritingMode oldWM = mFloatManager->Translate(wm, oPt);
mBCoord = std::max(mFloatManager->GetLowestFloatTop(wm, mContainerWidth),
mBCoord = std::max(mFloatManager->GetLowestFloatTop(wm, ContainerWidth()),
mBCoord);
// See if the float should clear any preceding floats...
@ -918,14 +926,14 @@ nsBlockReflowState::FlowAndPlaceFloat(nsIFrame* aFloat)
// If float is relatively positioned, factor that in as well
nsHTMLReflowState::ApplyRelativePositioning(aFloat, wm, floatOffsets,
&origin, mContainerWidth);
&origin, ContainerWidth());
// Position the float and make sure and views are properly
// positioned. We need to explicitly position its child views as
// well, since we're moving the float after flowing it.
bool moved = aFloat->GetLogicalPosition(wm, mContainerWidth) != origin;
bool moved = aFloat->GetLogicalPosition(wm, ContainerWidth()) != origin;
if (moved) {
aFloat->SetPosition(wm, origin, mContainerWidth);
aFloat->SetPosition(wm, origin, ContainerWidth());
nsContainerFrame::PositionFrameView(aFloat);
nsContainerFrame::PositionChildViews(aFloat);
}
@ -939,7 +947,7 @@ nsBlockReflowState::FlowAndPlaceFloat(nsIFrame* aFloat)
// calculate region
LogicalRect region =
nsFloatManager::CalculateRegionFor(wm, aFloat, floatMargin,
mContainerWidth);
ContainerWidth());
// if the float split, then take up all of the vertical height
if (NS_FRAME_IS_NOT_COMPLETE(reflowStatus) &&
(NS_UNCONSTRAINEDSIZE != ContentBSize())) {
@ -947,10 +955,10 @@ nsBlockReflowState::FlowAndPlaceFloat(nsIFrame* aFloat)
ContentBSize() - floatPos.B(wm));
}
DebugOnly<nsresult> rv = mFloatManager->AddFloat(aFloat, region, wm,
mContainerWidth);
ContainerWidth());
MOZ_ASSERT(NS_SUCCEEDED(rv), "bad float placement");
// store region
nsFloatManager::StoreRegionFor(wm, aFloat, region, mContainerWidth);
nsFloatManager::StoreRegionFor(wm, aFloat, region, ContainerWidth());
// If the float's dimensions have changed, note the damage in the
// float manager.
@ -1078,7 +1086,7 @@ nsBlockReflowState::ClearFloats(nscoord aBCoord, uint8_t aBreakType,
if (aBreakType != NS_STYLE_CLEAR_NONE) {
newBCoord = mFloatManager->ClearFloats(wm, newBCoord, aBreakType,
mContainerWidth, aFlags);
ContainerWidth(), aFlags);
}
if (aReplacedBlock) {

View File

@ -206,8 +206,10 @@ public:
return mContentArea.Size(wm).ConvertTo(aWM, wm);
}
// Physical width. Use only for physical <-> logical coordinate conversion.
nscoord mContainerWidth;
// Physical size. Use only for physical <-> logical coordinate conversion.
nsSize mContainerSize;
nscoord ContainerWidth() const { return mContainerSize.width; }
nscoord ContainerHeight() const { return mContainerSize.height; }
// Continuation out-of-flow float frames that need to move to our
// next in flow are placed here during reflow. It's a pointer to

View File

@ -420,13 +420,19 @@ nsBulletFrame::PaintBullet(nsRenderingContext& aRenderingContext, nsPoint aPt,
nscoord ascent = wm.IsLineInverted()
? fm->MaxDescent() : fm->MaxAscent();
aPt.MoveBy(padding.left, padding.top);
gfxContext *ctx = aRenderingContext.ThebesContext();
if (wm.IsVertical()) {
// XXX what about baseline snapping?
aPt.x += (wm.IsVerticalLR() ? ascent
: mRect.width - ascent);
if (wm.IsVerticalLR()) {
aPt.x = NSToCoordRound(nsLayoutUtils::GetSnappedBaselineX(
this, ctx, aPt.x, ascent));
} else {
aPt.x = NSToCoordRound(nsLayoutUtils::GetSnappedBaselineX(
this, ctx, aPt.x + mRect.width,
-ascent));
}
} else {
aPt.y = NSToCoordRound(nsLayoutUtils::GetSnappedBaselineY(
this, aRenderingContext.ThebesContext(), aPt.y, ascent));
this, ctx, aPt.y, ascent));
}
nsPresContext* presContext = PresContext();
if (!presContext->BidiEnabled() && HasRTLChars(text)) {

View File

@ -199,7 +199,8 @@ nsFirstLetterFrame::Reflow(nsPresContext* aPresContext,
ll.BeginLineReflow(bp.IStart(wm), bp.BStart(wm),
availSize.ISize(wm), NS_UNCONSTRAINEDSIZE,
false, true, kidWritingMode,
aReflowState.AvailableWidth());
nsSize(aReflowState.AvailableWidth(),
aReflowState.AvailableHeight()));
rs.mLineLayout = &ll;
ll.SetInFirstLetter(true);
ll.SetFirstLetterStyleOK(true);

View File

@ -5180,6 +5180,7 @@ nsIFrame::SchedulePaint(PaintType aType)
Layer*
nsIFrame::InvalidateLayer(uint32_t aDisplayItemKey,
const nsIntRect* aDamageRect,
const nsRect* aFrameDamageRect,
uint32_t aFlags /* = 0 */)
{
NS_ASSERTION(aDisplayItemKey > 0, "Need a key");
@ -5193,11 +5194,11 @@ nsIFrame::InvalidateLayer(uint32_t aDisplayItemKey,
return layer;
}
if (aDamageRect && aDamageRect->IsEmpty()) {
return layer;
}
if (!layer) {
if (aFrameDamageRect && aFrameDamageRect->IsEmpty()) {
return nullptr;
}
// Plugins can transition from not rendering anything to rendering,
// and still only call this. So always invalidate, with specifying
// the display item type just in case.
@ -5206,15 +5207,25 @@ nsIFrame::InvalidateLayer(uint32_t aDisplayItemKey,
// screen because sometimes we don't have any retainned data
// for remote type displayitem and thus Repaint event is not
// triggered. So, always invalidate here as well.
uint32_t displayItemKey = aDisplayItemKey;
if (aDisplayItemKey == nsDisplayItem::TYPE_PLUGIN ||
aDisplayItemKey == nsDisplayItem::TYPE_REMOTE) {
InvalidateFrame();
} else {
InvalidateFrame(aDisplayItemKey);
displayItemKey = 0;
}
if (aFrameDamageRect) {
InvalidateFrameWithRect(*aFrameDamageRect, displayItemKey);
} else {
InvalidateFrame(displayItemKey);
}
return nullptr;
}
if (aDamageRect && aDamageRect->IsEmpty()) {
return layer;
}
if (aDamageRect) {
layer->AddInvalidRect(*aDamageRect);
} else {

View File

@ -2224,6 +2224,9 @@ public:
* If no layer is found, calls InvalidateFrame() instead.
*
* @param aDamageRect Area of the layer to invalidate.
* @param aFrameDamageRect If no layer is found, the area of the frame to
* invalidate. If null, the entire frame will be
* invalidated.
* @param aDisplayItemKey Display item type.
* @param aFlags UPDATE_IS_ASYNC : Will skip the invalidation
* if the found layer is being composited by a remote
@ -2233,7 +2236,10 @@ public:
enum {
UPDATE_IS_ASYNC = 1 << 0
};
Layer* InvalidateLayer(uint32_t aDisplayItemKey, const nsIntRect* aDamageRect = nullptr, uint32_t aFlags = 0);
Layer* InvalidateLayer(uint32_t aDisplayItemKey,
const nsIntRect* aDamageRect = nullptr,
const nsRect* aFrameDamageRect = nullptr,
uint32_t aFlags = 0);
/**
* Returns a rect that encompasses everything that might be painted by

View File

@ -385,13 +385,8 @@ nsImageFrame::GetSourceToDestTransform(nsTransform2D& aTransform)
return false;
}
/*
* These two functions basically do the same check. The first one
* checks that the given request is the current request for our
* mContent. The second checks that the given image container the
* same as the image container on the current request for our
* mContent.
*/
// This function checks whether the given request is the current request for our
// mContent.
bool
nsImageFrame::IsPendingLoad(imgIRequest* aRequest) const
{
@ -405,33 +400,6 @@ nsImageFrame::IsPendingLoad(imgIRequest* aRequest) const
return requestType != nsIImageLoadingContent::CURRENT_REQUEST;
}
bool
nsImageFrame::IsPendingLoad(imgIContainer* aContainer) const
{
// default to pending load in case of errors
if (!aContainer) {
NS_ERROR("No image container!");
return true;
}
nsCOMPtr<nsIImageLoadingContent> imageLoader(do_QueryInterface(mContent));
NS_ASSERTION(imageLoader, "No image loading content?");
nsCOMPtr<imgIRequest> currentRequest;
imageLoader->GetRequest(nsIImageLoadingContent::CURRENT_REQUEST,
getter_AddRefs(currentRequest));
if (!currentRequest) {
NS_ERROR("No current request");
return true;
}
nsCOMPtr<imgIContainer> currentContainer;
currentRequest->GetImage(getter_AddRefs(currentContainer));
return currentContainer != aContainer;
}
nsRect
nsImageFrame::SourceRectToDest(const nsIntRect& aRect)
{
@ -633,15 +601,6 @@ nsImageFrame::OnSizeAvailable(imgIRequest* aRequest, imgIContainer* aImage)
nsresult
nsImageFrame::OnFrameUpdate(imgIRequest* aRequest, const nsIntRect* aRect)
{
if (mFirstFrameComplete) {
nsCOMPtr<imgIContainer> container;
aRequest->GetImage(getter_AddRefs(container));
return FrameChanged(aRequest, container);
}
// XXX do we need to make sure that the reflow from the OnSizeAvailable has
// been processed before we start calling invalidate?
NS_ENSURE_ARG_POINTER(aRect);
if (!(mState & IMAGE_GOTINITIALREFLOW)) {
@ -649,31 +608,45 @@ nsImageFrame::OnFrameUpdate(imgIRequest* aRequest, const nsIntRect* aRect)
return NS_OK;
}
if (mFirstFrameComplete && !StyleVisibility()->IsVisible()) {
return NS_OK;
}
if (IsPendingLoad(aRequest)) {
// We don't care
return NS_OK;
}
nsIntRect rect = mImage ? mImage->GetImageSpaceInvalidationRect(*aRect)
: *aRect;
nsIntRect layerInvalidRect = mImage
? mImage->GetImageSpaceInvalidationRect(*aRect)
: *aRect;
#ifdef DEBUG_decode
printf("Source rect (%d,%d,%d,%d)\n",
aRect->x, aRect->y, aRect->width, aRect->height);
#endif
if (rect.IsEqualInterior(nsIntRect::GetMaxSizedIntRect())) {
InvalidateFrame(nsDisplayItem::TYPE_IMAGE);
InvalidateFrame(nsDisplayItem::TYPE_ALT_FEEDBACK);
} else {
nsRect invalid = SourceRectToDest(rect);
InvalidateFrameWithRect(invalid, nsDisplayItem::TYPE_IMAGE);
InvalidateFrameWithRect(invalid, nsDisplayItem::TYPE_ALT_FEEDBACK);
if (layerInvalidRect.IsEqualInterior(nsIntRect::GetMaxSizedIntRect())) {
// Invalidate our entire area.
InvalidateSelf(nullptr, nullptr);
return NS_OK;
}
nsRect frameInvalidRect = SourceRectToDest(layerInvalidRect);
InvalidateSelf(&layerInvalidRect, &frameInvalidRect);
return NS_OK;
}
void
nsImageFrame::InvalidateSelf(const nsIntRect* aLayerInvalidRect,
const nsRect* aFrameInvalidRect)
{
InvalidateLayer(nsDisplayItem::TYPE_IMAGE,
aLayerInvalidRect,
aFrameInvalidRect);
if (!mFirstFrameComplete) {
InvalidateLayer(nsDisplayItem::TYPE_ALT_FEEDBACK,
aLayerInvalidRect,
aFrameInvalidRect);
}
}
nsresult
nsImageFrame::OnLoadComplete(imgIRequest* aRequest, nsresult aStatus)
{
@ -730,23 +703,6 @@ nsImageFrame::NotifyNewCurrentRequest(imgIRequest *aRequest,
}
}
nsresult
nsImageFrame::FrameChanged(imgIRequest *aRequest,
imgIContainer *aContainer)
{
if (!StyleVisibility()->IsVisible()) {
return NS_OK;
}
if (IsPendingLoad(aContainer)) {
// We don't care about it
return NS_OK;
}
InvalidateLayer(nsDisplayItem::TYPE_IMAGE);
return NS_OK;
}
void
nsImageFrame::EnsureIntrinsicSizeAndRatio()
{

View File

@ -226,8 +226,7 @@ protected:
nsresult OnSizeAvailable(imgIRequest* aRequest, imgIContainer* aImage);
nsresult OnFrameUpdate(imgIRequest* aRequest, const nsIntRect* aRect);
nsresult OnLoadComplete(imgIRequest* aRequest, nsresult aStatus);
nsresult FrameChanged(imgIRequest *aRequest,
imgIContainer *aContainer);
/**
* Notification that aRequest will now be the current request.
*/
@ -272,12 +271,11 @@ private:
bool GetSourceToDestTransform(nsTransform2D& aTransform);
/**
* Helper functions to check whether the request or image container
* corresponds to a load we don't care about. Most of the decoder
* observer methods will bail early if these return true.
* Helper function to check whether the request corresponds to a load we don't
* care about. Most of the decoder observer methods will bail early if this
* returns true.
*/
bool IsPendingLoad(imgIRequest* aRequest) const;
bool IsPendingLoad(imgIContainer* aContainer) const;
/**
* Function to convert a dirty rect in the source image to a dirty
@ -285,6 +283,18 @@ private:
*/
nsRect SourceRectToDest(const nsIntRect & aRect);
/**
* Triggers invalidation for both our image display item and, if appropriate,
* our alt-feedback display item.
*
* @param aLayerInvalidRect The area to invalidate in layer space. If null, the
* entire layer will be invalidated.
* @param aFrameInvalidRect The area to invalidate in frame space. If null, the
* entire frame will be invalidated.
*/
void InvalidateSelf(const nsIntRect* aLayerInvalidRect,
const nsRect* aFrameInvalidRect);
nsImageMap* mImageMap;
nsCOMPtr<imgINotificationObserver> mListener;

View File

@ -152,7 +152,7 @@ nsLineLayout::BeginLineReflow(nscoord aICoord, nscoord aBCoord,
bool aImpactedByFloats,
bool aIsTopOfPage,
WritingMode aWritingMode,
nscoord aContainerWidth)
const nsSize& aContainerSize)
{
NS_ASSERTION(nullptr == mRootSpan, "bad linelayout user");
NS_WARN_IF_FALSE(aISize != NS_UNCONSTRAINEDSIZE,
@ -207,7 +207,7 @@ nsLineLayout::BeginLineReflow(nscoord aICoord, nscoord aBCoord,
psd->mIStart = aICoord;
psd->mICoord = aICoord;
psd->mIEnd = aICoord + aISize;
mContainerWidth = aContainerWidth;
mContainerSize = aContainerSize;
// If we're in a constrained height frame, then we don't allow a
// max line box width to take effect.
@ -241,10 +241,6 @@ nsLineLayout::BeginLineReflow(nscoord aICoord, nscoord aBCoord,
if (textIndent.HasPercent()) {
pctBasis =
nsHTMLReflowState::GetContainingBlockContentWidth(mBlockReflowState);
if (mGotLineBox) {
mLineBox->DisableResizeReflowOptimization();
}
}
nscoord indent = nsRuleNode::ComputeCoordPercentCalc(textIndent, pctBasis);
@ -321,7 +317,7 @@ nsLineLayout::UpdateBand(WritingMode aWM,
// need to convert to our writing mode, because we might have a different
// mode from the caller due to dir: auto
LogicalRect availSpace = aNewAvailSpace.ConvertTo(lineWM, aWM,
mContainerWidth);
ContainerWidth());
#ifdef REALLY_NOISY_REFLOW
printf("nsLL::UpdateBand %d, %d, %d, %d, (converted to %d, %d, %d, %d); frame=%p\n will set mImpacted to true\n",
aNewAvailSpace.x, aNewAvailSpace.y,
@ -1488,7 +1484,7 @@ nsLineLayout::AddBulletFrame(nsIFrame* aFrame,
}
// Note: block-coord value will be updated during block-direction alignment
pfd->mBounds = LogicalRect(lineWM, aFrame->GetRect(), mContainerWidth);
pfd->mBounds = LogicalRect(lineWM, aFrame->GetRect(), ContainerWidth());
pfd->mOverflowAreas = aMetrics.mOverflowAreas;
}
@ -1504,7 +1500,7 @@ nsLineLayout::DumpPerSpanData(PerSpanData* psd, int32_t aIndent)
nsFrame::IndentBy(stdout, aIndent+1);
nsFrame::ListTag(stdout, pfd->mFrame);
nsRect rect = pfd->mBounds.GetPhysicalRect(psd->mWritingMode,
mContainerWidth);
ContainerWidth());
printf(" %d,%d,%d,%d\n", rect.x, rect.y, rect.width, rect.height);
if (pfd->mSpan) {
DumpPerSpanData(pfd->mSpan, aIndent + 1);
@ -1593,7 +1589,7 @@ nsLineLayout::VerticalAlignLine()
for (PerFrameData* pfd = psd->mFirstFrame; pfd; pfd = pfd->mNext) {
if (pfd->mBlockDirAlign == VALIGN_OTHER) {
pfd->mBounds.BStart(lineWM) += baselineBCoord;
pfd->mFrame->SetRect(lineWM, pfd->mBounds, mContainerWidth);
pfd->mFrame->SetRect(lineWM, pfd->mBounds, ContainerWidth());
}
}
PlaceTopBottomFrames(psd, -mBStartEdge, lineBSize);
@ -1604,7 +1600,7 @@ nsLineLayout::VerticalAlignLine()
mLineBox->SetBounds(lineWM,
psd->mIStart, mBStartEdge,
psd->mICoord - psd->mIStart, lineBSize,
mContainerWidth);
ContainerWidth());
mLineBox->SetLogicalAscent(baselineBCoord - mBStartEdge);
#ifdef NOISY_BLOCKDIR_ALIGN
@ -3037,17 +3033,17 @@ nsLineLayout::TextAlignLine(nsLineBox* aLine,
(!mPresContext->IsVisualMode() || !lineWM.IsBidiLTR())) {
nsBidiPresUtils::ReorderFrames(psd->mFirstFrame->mFrame,
aLine->GetChildCount(),
lineWM, mContainerWidth,
lineWM, mContainerSize,
psd->mIStart + mTextIndent + dx);
if (dx) {
aLine->IndentBy(dx, mContainerWidth);
aLine->IndentBy(dx, ContainerWidth());
}
} else if (dx) {
for (PerFrameData* pfd = psd->mFirstFrame; pfd; pfd = pfd->mNext) {
pfd->mBounds.IStart(lineWM) += dx;
pfd->mFrame->SetRect(lineWM, pfd->mBounds, ContainerWidthForSpan(psd));
}
aLine->IndentBy(dx, mContainerWidth);
aLine->IndentBy(dx, ContainerWidth());
}
}
@ -3061,13 +3057,13 @@ nsLineLayout::ApplyRelativePositioning(PerFrameData* aPFD)
nsIFrame* frame = aPFD->mFrame;
WritingMode frameWM = frame->GetWritingMode();
LogicalPoint origin = frame->GetLogicalPosition(mContainerWidth);
LogicalPoint origin = frame->GetLogicalPosition(ContainerWidth());
// right and bottom are handled by
// nsHTMLReflowState::ComputeRelativeOffsets
nsHTMLReflowState::ApplyRelativePositioning(frame, frameWM,
aPFD->mOffsets, &origin,
mContainerWidth);
frame->SetPosition(frameWM, origin, mContainerWidth);
ContainerWidth());
frame->SetPosition(frameWM, origin, ContainerWidth());
}
// This method do relative positioning for ruby annotations.
@ -3120,7 +3116,7 @@ nsLineLayout::RelativePositionFrames(PerSpanData* psd, nsOverflowAreas& aOverflo
// children of the block starts at the upper left corner of the
// line and is sized to match the size of the line's bounding box
// (the same size as the values returned from VerticalAlignFrames)
overflowAreas.VisualOverflow() = rect.GetPhysicalRect(wm, mContainerWidth);
overflowAreas.VisualOverflow() = rect.GetPhysicalRect(wm, ContainerWidth());
overflowAreas.ScrollableOverflow() = overflowAreas.VisualOverflow();
}

View File

@ -56,7 +56,7 @@ public:
bool aImpactedByFloats,
bool aIsTopOfPage,
mozilla::WritingMode aWritingMode,
nscoord aContainerWidth);
const nsSize& aContainerSize);
void EndLineReflow();
@ -549,11 +549,11 @@ protected:
// The container width to use when converting between logical and
// physical coordinates for frames in this span. For the root span
// this is the width of the block cached in mContainerWidth; for
// this is the width of the block cached in mContainerSize.width; for
// child spans it's the width of the root span
nscoord ContainerWidthForSpan(PerSpanData* aPSD) {
return (aPSD == mRootSpan)
? mContainerWidth
? ContainerWidth()
: aPSD->mFrame->mBounds.Width(mRootSpan->mWritingMode);
}
@ -588,8 +588,10 @@ protected:
// frame, if any
nscoord mTrimmableISize;
// Physical width. Use only for physical <-> logical coordinate conversion.
nscoord mContainerWidth;
// Physical size. Use only for physical <-> logical coordinate conversion.
nsSize mContainerSize;
nscoord ContainerWidth() const { return mContainerSize.width; }
nscoord ContainerHeight() const { return mContainerSize.height; }
bool mFirstLetterStyleOK : 1;
bool mIsTopOfPage : 1;

View File

@ -387,10 +387,10 @@ nsRubyBaseContainerFrame::Reflow(nsPresContext* aPresContext,
// Border and padding are suppressed on ruby text containers.
// If the writing mode is vertical-rl, the horizontal position of
// rt frames will be updated when reflowing this text container,
// hence leave container width 0 here for now.
// hence leave container size 0 here for now.
lineLayout->BeginLineReflow(0, 0, reflowState->ComputedISize(),
NS_UNCONSTRAINEDSIZE,
false, false, lineWM, 0);
false, false, lineWM, nsSize(0, 0));
lineLayout->AttachRootFrameToBaseLineLayout();
}

View File

@ -6128,9 +6128,15 @@ nsTextFrame::PaintText(nsRenderingContext* aRenderingContext, nsPoint aPt,
gfxPoint framePt(aPt.x, aPt.y);
gfxPoint textBaselinePt;
if (verticalRun) {
textBaselinePt = // XXX sideways-left will need different handling here
gfxPoint(aPt.x + (wm.IsVerticalLR() ? mAscent : frameWidth - mAscent),
rtl ? aPt.y + GetSize().height : aPt.y);
if (wm.IsVerticalLR()) {
textBaselinePt.x =
nsLayoutUtils::GetSnappedBaselineX(this, ctx, aPt.x, mAscent);
} else {
textBaselinePt.x =
nsLayoutUtils::GetSnappedBaselineX(this, ctx, aPt.x + frameWidth,
-mAscent);
}
textBaselinePt.y = rtl ? aPt.y + GetSize().height : aPt.y;
} else {
textBaselinePt = gfxPoint(rtl ? gfxFloat(aPt.x + frameWidth) : framePt.x,
nsLayoutUtils::GetSnappedBaselineY(this, ctx, aPt.y, mAscent));

View File

@ -16,3 +16,4 @@
== text-indent-intrinsic-min.html text-indent-intrinsic-min-ref.html
== text-indent-negative-intrinsic-pref.html text-indent-negative-intrinsic-pref-ref.html
== text-indent-negative-intrinsic-min.html text-indent-negative-intrinsic-min-ref.html
== text-indent-parent-dynamic.html text-indent-parent-dynamic-ref.html

View File

@ -0,0 +1,10 @@
<!DOCTYPE html>
<html>
<body>
<div id="x" style="background: lightgreen; height: 3em; width: 500px; padding: 4px;">
<div style="text-indent: 200px; width: 200px; background: yellow;">X</div>
</div>
</body>
</html>

View File

@ -0,0 +1,15 @@
<!DOCTYPE html>
<html>
<body>
<div id="x" style="background: lightgreen; height: 3em; width: 400px; padding: 4px;">
<div style="text-indent: 40%; width: 200px; background: yellow;">X</div>
</div>
<script>
var x = document.getElementById('x');
x.offsetWidth;
x.style.width = '500px';
</script>
</body>
</html>

View File

@ -0,0 +1,47 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<style>
@font-face {
font-family: ahem;
src: url(../fonts/Ahem.ttf);
}
div {
font-family: ahem;
font-size: 10px;
}
.lr {
writing-mode: vertical-lr;
text-orientation: sideways-right;
height: 40px;
}
.rl {
writing-mode: vertical-lr;
text-orientation: sideways-right;
height: 40px;
}
.c { position: relative; top: 10px; left: 10px; }
</style>
</head>
<body>
<div class="lr c">abc<br>abc<br>abc<br>abc<br>abc<br>abc<br>abc<br>abc<br>abc</div>
<div class="lr c">abc<br>abc<br>abc<br>abc<br>abc<br>abc<br>abc<br>abc<br>abc</div>
<div class="lr c">abc<br>abc<br>abc<br>abc<br>abc<br>abc<br>abc<br>abc<br>abc</div>
<div class="lr c">abc<br>abc<br>abc<br>abc<br>abc<br>abc<br>abc<br>abc<br>abc</div>
<div class="lr c">abc<br>abc<br>abc<br>abc<br>abc<br>abc<br>abc<br>abc<br>abc</div>
<br>
<div class="rl c">abc<br>abc<br>abc<br>abc<br>abc<br>abc<br>abc<br>abc<br>abc</div>
<div class="rl c">abc<br>abc<br>abc<br>abc<br>abc<br>abc<br>abc<br>abc<br>abc</div>
<div class="rl c">abc<br>abc<br>abc<br>abc<br>abc<br>abc<br>abc<br>abc<br>abc</div>
<div class="rl c">abc<br>abc<br>abc<br>abc<br>abc<br>abc<br>abc<br>abc<br>abc</div>
<div class="rl c">abc<br>abc<br>abc<br>abc<br>abc<br>abc<br>abc<br>abc<br>abc</div>
</body>
</html>

View File

@ -0,0 +1,82 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<style>
@font-face {
font-family: ahem;
src: url(../fonts/Ahem.ttf);
}
div {
font-family: ahem;
font-size: 10px;
}
.lr {
writing-mode: vertical-lr;
text-orientation: sideways-right;
height: 40px;
}
.rl {
writing-mode: vertical-rl;
text-orientation: sideways-right;
height: 40px;
}
.a { position: relative; top: 10px; left: 10px; }
.b { position: relative; top: 10px; left: 10px; }
.c { position: relative; top: 10px; left: 10px; }
.d { position: relative; top: 10px; left: 10px; }
.e { position: relative; top: 10px; left: 10px; }
/* resolution-dependent offsets: we want CSS px values that will correspond
to less that 0.5 device pixels either side of where 10px falls, so they
all snap to the same device-pixel value */
/* XXX For higher-than-retina density, we punt; the test becomes a no-op */
@media (max-resolution: 2dppx) {
.a { left: 9.8px; }
.b { left: 9.9px; }
.c { left: 10px; }
.d { left: 10.1px; }
.e { left: 10.2px; }
}
@media (max-resolution: 1.5dppx) {
.a { left: 9.7px; }
.b { left: 9.85px; }
.c { left: 10px; }
.d { left: 10.15px; }
.e { left: 10.3px; }
}
@media (max-resolution: 1dppx) {
.a { left: 9.6px; }
.b { left: 9.8px; }
.c { left: 10px; }
.d { left: 10.2px; }
.e { left: 10.4px; }
}
</style>
</head>
<body>
<div class="lr a">abc<br>abc<br>abc<br>abc<br>abc<br>abc<br>abc<br>abc<br>abc</div>
<div class="lr b">abc<br>abc<br>abc<br>abc<br>abc<br>abc<br>abc<br>abc<br>abc</div>
<div class="lr c">abc<br>abc<br>abc<br>abc<br>abc<br>abc<br>abc<br>abc<br>abc</div>
<div class="lr d">abc<br>abc<br>abc<br>abc<br>abc<br>abc<br>abc<br>abc<br>abc</div>
<div class="lr e">abc<br>abc<br>abc<br>abc<br>abc<br>abc<br>abc<br>abc<br>abc</div>
<br>
<div class="rl a">abc<br>abc<br>abc<br>abc<br>abc<br>abc<br>abc<br>abc<br>abc</div>
<div class="rl b">abc<br>abc<br>abc<br>abc<br>abc<br>abc<br>abc<br>abc<br>abc</div>
<div class="rl c">abc<br>abc<br>abc<br>abc<br>abc<br>abc<br>abc<br>abc<br>abc</div>
<div class="rl d">abc<br>abc<br>abc<br>abc<br>abc<br>abc<br>abc<br>abc<br>abc</div>
<div class="rl e">abc<br>abc<br>abc<br>abc<br>abc<br>abc<br>abc<br>abc<br>abc</div>
</body>
</html>

View File

@ -0,0 +1,20 @@
<!DOCTYPE html>
<html>
<head>
<title>CSS Reftest Reference</title>
<link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
<style type="text/css">
body {
margin: 0;
}
div {
position: absolute;
left: 0px;
top: 200px;
}
</style>
</head>
<body>
<div><img src="green-100x100.png" width="100" height="100" alt="Image download support must be enabled"></img></div>
</body>
</html>

View File

@ -0,0 +1,20 @@
<!DOCTYPE html>
<html>
<head>
<title>CSS Reftest Reference</title>
<link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
<style type="text/css">
body {
margin: 0;
}
div {
position: absolute;
left: 200px;
top: 200px;
}
</style>
</head>
<body>
<div><img src="green-100x100.png" width="100" height="100" alt="Image download support must be enabled"></img></div>
</body>
</html>

View File

@ -0,0 +1,30 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>CSS Writing Modes</title>
<link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
<link rel="help" href="http://www.w3.org/TR/css-writing-modes-3/#vertical-layout" title="7.1 Principles of Layout in Vertical Writing Modes">
<style type="text/css">
body {
margin: 0;
}
div.outer {
background: red url("left-top-300x300.png");
height: 300px;
width: 300px;
writing-mode: horizontal-tb;
direction: ltr;
}
div.inner {
display: inline-block;
background-color: green;
height: 100px;
width: 100px;
}
</style>
</head>
<body>
<div class="outer"><div class="inner"></div></div>
</body>
</html>

View File

@ -0,0 +1,30 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>CSS Writing Modes</title>
<link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
<link rel="help" href="http://www.w3.org/TR/css-writing-modes-3/#vertical-layout" title="7.1 Principles of Layout in Vertical Writing Modes">
<style type="text/css">
body {
margin: 0;
}
div.outer {
background: red url("right-top-300x300.png");
height: 300px;
width: 300px;
writing-mode: horizontal-tb;
direction: rtl;
}
div.inner {
display: inline-block;
background-color: green;
height: 100px;
width: 100px;
}
</style>
</head>
<body>
<div class="outer"><div class="inner"></div></div>
</body>
</html>

View File

@ -0,0 +1,30 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>CSS Writing Modes</title>
<link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
<link rel="help" href="http://www.w3.org/TR/css-writing-modes-3/#vertical-layout" title="7.1 Principles of Layout in Vertical Writing Modes">
<style type="text/css">
body {
margin: 0;
}
div.outer {
background: red url("left-top-300x300.png");
height: 300px;
width: 300px;
writing-mode: vertical-lr;
direction: ltr;
}
div.inner {
display: inline-block;
background-color: green;
height: 100px;
width: 100px;
}
</style>
</head>
<body>
<div class="outer"><div class="inner"></div></div>
</body>
</html>

View File

@ -0,0 +1,30 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>CSS Writing Modes</title>
<link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
<link rel="help" href="http://www.w3.org/TR/css-writing-modes-3/#vertical-layout" title="7.1 Principles of Layout in Vertical Writing Modes">
<style type="text/css">
body {
margin: 0;
}
div.outer {
background: red url("left-bottom-300x300.png");
height: 300px;
width: 300px;
writing-mode: vertical-lr;
direction: rtl;
}
div.inner {
display: inline-block;
background-color: green;
height: 100px;
width: 100px;
}
</style>
</head>
<body>
<div class="outer"><div class="inner"></div></div>
</body>
</html>

View File

@ -0,0 +1,30 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>CSS Writing Modes</title>
<link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
<link rel="help" href="http://www.w3.org/TR/css-writing-modes-3/#vertical-layout" title="7.1 Principles of Layout in Vertical Writing Modes">
<style type="text/css">
body {
margin: 0;
}
div.outer {
background: red url("right-top-300x300.png");
height: 300px;
width: 300px;
writing-mode: vertical-rl;
direction: ltr;
}
div.inner {
display: inline-block;
background-color: green;
height: 100px;
width: 100px;
}
</style>
</head>
<body>
<div class="outer"><div class="inner"></div></div>
</body>
</html>

View File

@ -0,0 +1,30 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>CSS Writing Modes</title>
<link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
<link rel="help" href="http://www.w3.org/TR/css-writing-modes-3/#vertical-layout" title="7.1 Principles of Layout in Vertical Writing Modes">
<style type="text/css">
body {
margin: 0;
}
div.outer {
background: red url("right-bottom-300x300.png");
height: 300px;
width: 300px;
writing-mode: vertical-rl;
direction: rtl;
}
div.inner {
display: inline-block;
background-color: green;
height: 100px;
width: 100px;
}
</style>
</head>
<body>
<div class="outer"><div class="inner"></div></div>
</body>
</html>

View File

@ -0,0 +1,31 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>CSS Writing Modes</title>
<link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
<link rel="help" href="http://www.w3.org/TR/css-writing-modes-3/#vertical-layout" title="7.1 Principles of Layout in Vertical Writing Modes">
<style type="text/css">
body {
margin: 0;
}
div.outer {
background: red url("right-top-300x300.png");
height: 300px;
width: 300px;
text-align: end;
writing-mode: horizontal-tb;
direction: ltr;
}
div.inner {
display: inline-block;
background-color: green;
height: 100px;
width: 100px;
}
</style>
</head>
<body>
<div class="outer"><div class="inner"></div></div>
</body>
</html>

View File

@ -0,0 +1,31 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>CSS Writing Modes</title>
<link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
<link rel="help" href="http://www.w3.org/TR/css-writing-modes-3/#vertical-layout" title="7.1 Principles of Layout in Vertical Writing Modes">
<style type="text/css">
body {
margin: 0;
}
div.outer {
background: red url("left-top-300x300.png");
height: 300px;
width: 300px;
text-align: end;
writing-mode: horizontal-tb;
direction: rtl;
}
div.inner {
display: inline-block;
background-color: green;
height: 100px;
width: 100px;
}
</style>
</head>
<body>
<div class="outer"><div class="inner"></div></div>
</body>
</html>

View File

@ -0,0 +1,31 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>CSS Writing Modes</title>
<link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
<link rel="help" href="http://www.w3.org/TR/css-writing-modes-3/#vertical-layout" title="7.1 Principles of Layout in Vertical Writing Modes">
<style type="text/css">
body {
margin: 0;
}
div.outer {
background: red url("left-bottom-300x300.png");
height: 300px;
width: 300px;
text-align: end;
writing-mode: vertical-lr;
direction: ltr;
}
div.inner {
display: inline-block;
background-color: green;
height: 100px;
width: 100px;
}
</style>
</head>
<body>
<div class="outer"><div class="inner"></div></div>
</body>
</html>

View File

@ -0,0 +1,31 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>CSS Writing Modes</title>
<link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
<link rel="help" href="http://www.w3.org/TR/css-writing-modes-3/#vertical-layout" title="7.1 Principles of Layout in Vertical Writing Modes">
<style type="text/css">
body {
margin: 0;
}
div.outer {
background: red url("left-top-300x300.png");
height: 300px;
width: 300px;
text-align: end;
writing-mode: vertical-lr;
direction: rtl;
}
div.inner {
display: inline-block;
background-color: green;
height: 100px;
width: 100px;
}
</style>
</head>
<body>
<div class="outer"><div class="inner"></div></div>
</body>
</html>

View File

@ -0,0 +1,31 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>CSS Writing Modes</title>
<link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
<link rel="help" href="http://www.w3.org/TR/css-writing-modes-3/#vertical-layout" title="7.1 Principles of Layout in Vertical Writing Modes">
<style type="text/css">
body {
margin: 0;
}
div.outer {
background: red url("right-bottom-300x300.png");
height: 300px;
width: 300px;
text-align: end;
writing-mode: vertical-rl;
direction: ltr;
}
div.inner {
display: inline-block;
background-color: green;
height: 100px;
width: 100px;
}
</style>
</head>
<body>
<div class="outer"><div class="inner"></div></div>
</body>
</html>

View File

@ -0,0 +1,31 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>CSS Writing Modes</title>
<link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
<link rel="help" href="http://www.w3.org/TR/css-writing-modes-3/#vertical-layout" title="7.1 Principles of Layout in Vertical Writing Modes">
<style type="text/css">
body {
margin: 0;
}
div.outer {
background: red url("right-top-300x300.png");
height: 300px;
width: 300px;
text-align: end;
writing-mode: vertical-rl;
direction: rtl;
}
div.inner {
display: inline-block;
background-color: green;
height: 100px;
width: 100px;
}
</style>
</head>
<body>
<div class="outer"><div class="inner"></div></div>
</body>
</html>

View File

@ -0,0 +1,31 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>CSS Writing Modes</title>
<link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
<link rel="help" href="http://www.w3.org/TR/css-writing-modes-3/#vertical-layout" title="7.1 Principles of Layout in Vertical Writing Modes">
<style type="text/css">
body {
margin: 0;
}
div.outer {
background: red url("left-top-300x300.png");
height: 300px;
width: 300px;
text-align: left;
writing-mode: horizontal-tb;
direction: ltr;
}
div.inner {
display: inline-block;
background-color: green;
height: 100px;
width: 100px;
}
</style>
</head>
<body>
<div class="outer"><div class="inner"></div></div>
</body>
</html>

View File

@ -0,0 +1,31 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>CSS Writing Modes</title>
<link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
<link rel="help" href="http://www.w3.org/TR/css-writing-modes-3/#vertical-layout" title="7.1 Principles of Layout in Vertical Writing Modes">
<style type="text/css">
body {
margin: 0;
}
div.outer {
background: red url("left-top-300x300.png");
height: 300px;
width: 300px;
text-align: left;
writing-mode: horizontal-tb;
direction: rtl;
}
div.inner {
display: inline-block;
background-color: green;
height: 100px;
width: 100px;
}
</style>
</head>
<body>
<div class="outer"><div class="inner"></div></div>
</body>
</html>

View File

@ -0,0 +1,31 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>CSS Writing Modes</title>
<link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
<link rel="help" href="http://www.w3.org/TR/css-writing-modes-3/#vertical-layout" title="7.1 Principles of Layout in Vertical Writing Modes">
<style type="text/css">
body {
margin: 0;
}
div.outer {
background: red url("left-top-300x300.png");
height: 300px;
width: 300px;
text-align: left;
writing-mode: vertical-lr;
direction: ltr;
}
div.inner {
display: inline-block;
background-color: green;
height: 100px;
width: 100px;
}
</style>
</head>
<body>
<div class="outer"><div class="inner"></div></div>
</body>
</html>

View File

@ -0,0 +1,31 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>CSS Writing Modes</title>
<link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
<link rel="help" href="http://www.w3.org/TR/css-writing-modes-3/#vertical-layout" title="7.1 Principles of Layout in Vertical Writing Modes">
<style type="text/css">
body {
margin: 0;
}
div.outer {
background: red url("left-top-300x300.png");
height: 300px;
width: 300px;
text-align: left;
writing-mode: vertical-lr;
direction: rtl;
}
div.inner {
display: inline-block;
background-color: green;
height: 100px;
width: 100px;
}
</style>
</head>
<body>
<div class="outer"><div class="inner"></div></div>
</body>
</html>

View File

@ -0,0 +1,31 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>CSS Writing Modes</title>
<link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
<link rel="help" href="http://www.w3.org/TR/css-writing-modes-3/#vertical-layout" title="7.1 Principles of Layout in Vertical Writing Modes">
<style type="text/css">
body {
margin: 0;
}
div.outer {
background: red url("right-top-300x300.png");
height: 300px;
width: 300px;
text-align: left;
writing-mode: vertical-rl;
direction: ltr;
}
div.inner {
display: inline-block;
background-color: green;
height: 100px;
width: 100px;
}
</style>
</head>
<body>
<div class="outer"><div class="inner"></div></div>
</body>
</html>

View File

@ -0,0 +1,31 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>CSS Writing Modes</title>
<link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
<link rel="help" href="http://www.w3.org/TR/css-writing-modes-3/#vertical-layout" title="7.1 Principles of Layout in Vertical Writing Modes">
<style type="text/css">
body {
margin: 0;
}
div.outer {
background: red url("right-top-300x300.png");
height: 300px;
width: 300px;
text-align: left;
writing-mode: vertical-rl;
direction: rtl;
}
div.inner {
display: inline-block;
background-color: green;
height: 100px;
width: 100px;
}
</style>
</head>
<body>
<div class="outer"><div class="inner"></div></div>
</body>
</html>

View File

@ -0,0 +1,31 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>CSS Writing Modes</title>
<link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
<link rel="help" href="http://www.w3.org/TR/css-writing-modes-3/#vertical-layout" title="7.1 Principles of Layout in Vertical Writing Modes">
<style type="text/css">
body {
margin: 0;
}
div.outer {
background: red url("right-top-300x300.png");
height: 300px;
width: 300px;
text-align: right;
writing-mode: horizontal-tb;
direction: ltr;
}
div.inner {
display: inline-block;
background-color: green;
height: 100px;
width: 100px;
}
</style>
</head>
<body>
<div class="outer"><div class="inner"></div></div>
</body>
</html>

View File

@ -0,0 +1,31 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>CSS Writing Modes</title>
<link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
<link rel="help" href="http://www.w3.org/TR/css-writing-modes-3/#vertical-layout" title="7.1 Principles of Layout in Vertical Writing Modes">
<style type="text/css">
body {
margin: 0;
}
div.outer {
background: red url("right-top-300x300.png");
height: 300px;
width: 300px;
text-align: right;
writing-mode: horizontal-tb;
direction: rtl;
}
div.inner {
display: inline-block;
background-color: green;
height: 100px;
width: 100px;
}
</style>
</head>
<body>
<div class="outer"><div class="inner"></div></div>
</body>
</html>

View File

@ -0,0 +1,31 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>CSS Writing Modes</title>
<link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
<link rel="help" href="http://www.w3.org/TR/css-writing-modes-3/#vertical-layout" title="7.1 Principles of Layout in Vertical Writing Modes">
<style type="text/css">
body {
margin: 0;
}
div.outer {
background: red url("left-bottom-300x300.png");
height: 300px;
width: 300px;
text-align: right;
writing-mode: vertical-lr;
direction: ltr;
}
div.inner {
display: inline-block;
background-color: green;
height: 100px;
width: 100px;
}
</style>
</head>
<body>
<div class="outer"><div class="inner"></div></div>
</body>
</html>

View File

@ -0,0 +1,31 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>CSS Writing Modes</title>
<link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
<link rel="help" href="http://www.w3.org/TR/css-writing-modes-3/#vertical-layout" title="7.1 Principles of Layout in Vertical Writing Modes">
<style type="text/css">
body {
margin: 0;
}
div.outer {
background: red url("left-bottom-300x300.png");
height: 300px;
width: 300px;
text-align: right;
writing-mode: vertical-lr;
direction: rtl;
}
div.inner {
display: inline-block;
background-color: green;
height: 100px;
width: 100px;
}
</style>
</head>
<body>
<div class="outer"><div class="inner"></div></div>
</body>
</html>

View File

@ -0,0 +1,31 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>CSS Writing Modes</title>
<link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
<link rel="help" href="http://www.w3.org/TR/css-writing-modes-3/#vertical-layout" title="7.1 Principles of Layout in Vertical Writing Modes">
<style type="text/css">
body {
margin: 0;
}
div.outer {
background: red url("right-bottom-300x300.png");
height: 300px;
width: 300px;
text-align: right;
writing-mode: vertical-rl;
direction: ltr;
}
div.inner {
display: inline-block;
background-color: green;
height: 100px;
width: 100px;
}
</style>
</head>
<body>
<div class="outer"><div class="inner"></div></div>
</body>
</html>

View File

@ -0,0 +1,31 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>CSS Writing Modes</title>
<link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
<link rel="help" href="http://www.w3.org/TR/css-writing-modes-3/#vertical-layout" title="7.1 Principles of Layout in Vertical Writing Modes">
<style type="text/css">
body {
margin: 0;
}
div.outer {
background: red url("right-bottom-300x300.png");
height: 300px;
width: 300px;
text-align: right;
writing-mode: vertical-rl;
direction: rtl;
}
div.inner {
display: inline-block;
background-color: green;
height: 100px;
width: 100px;
}
</style>
</head>
<body>
<div class="outer"><div class="inner"></div></div>
</body>
</html>

View File

@ -0,0 +1,31 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>CSS Writing Modes</title>
<link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
<link rel="help" href="http://www.w3.org/TR/css-writing-modes-3/#vertical-layout" title="7.1 Principles of Layout in Vertical Writing Modes">
<style type="text/css">
body {
margin: 0;
}
div.outer {
background: red url("left-top-300x300.png");
height: 300px;
width: 300px;
text-align: start;
writing-mode: horizontal-tb;
direction: ltr;
}
div.inner {
display: inline-block;
background-color: green;
height: 100px;
width: 100px;
}
</style>
</head>
<body>
<div class="outer"><div class="inner"></div></div>
</body>
</html>

View File

@ -0,0 +1,31 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>CSS Writing Modes</title>
<link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
<link rel="help" href="http://www.w3.org/TR/css-writing-modes-3/#vertical-layout" title="7.1 Principles of Layout in Vertical Writing Modes">
<style type="text/css">
body {
margin: 0;
}
div.outer {
background: red url("right-top-300x300.png");
height: 300px;
width: 300px;
text-align: start;
writing-mode: horizontal-tb;
direction: rtl;
}
div.inner {
display: inline-block;
background-color: green;
height: 100px;
width: 100px;
}
</style>
</head>
<body>
<div class="outer"><div class="inner"></div></div>
</body>
</html>

View File

@ -0,0 +1,31 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>CSS Writing Modes</title>
<link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
<link rel="help" href="http://www.w3.org/TR/css-writing-modes-3/#vertical-layout" title="7.1 Principles of Layout in Vertical Writing Modes">
<style type="text/css">
body {
margin: 0;
}
div.outer {
background: red url("left-top-300x300.png");
height: 300px;
width: 300px;
text-align: start;
writing-mode: vertical-lr;
direction: ltr;
}
div.inner {
display: inline-block;
background-color: green;
height: 100px;
width: 100px;
}
</style>
</head>
<body>
<div class="outer"><div class="inner"></div></div>
</body>
</html>

View File

@ -0,0 +1,31 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>CSS Writing Modes</title>
<link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
<link rel="help" href="http://www.w3.org/TR/css-writing-modes-3/#vertical-layout" title="7.1 Principles of Layout in Vertical Writing Modes">
<style type="text/css">
body {
margin: 0;
}
div.outer {
background: red url("left-bottom-300x300.png");
height: 300px;
width: 300px;
text-align: start;
writing-mode: vertical-lr;
direction: rtl;
}
div.inner {
display: inline-block;
background-color: green;
height: 100px;
width: 100px;
}
</style>
</head>
<body>
<div class="outer"><div class="inner"></div></div>
</body>
</html>

View File

@ -0,0 +1,31 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>CSS Writing Modes</title>
<link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
<link rel="help" href="http://www.w3.org/TR/css-writing-modes-3/#vertical-layout" title="7.1 Principles of Layout in Vertical Writing Modes">
<style type="text/css">
body {
margin: 0;
}
div.outer {
background: red url("right-top-300x300.png");
height: 300px;
width: 300px;
text-align: start;
writing-mode: vertical-rl;
direction: ltr;
}
div.inner {
display: inline-block;
background-color: green;
height: 100px;
width: 100px;
}
</style>
</head>
<body>
<div class="outer"><div class="inner"></div></div>
</body>
</html>

View File

@ -0,0 +1,31 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>CSS Writing Modes</title>
<link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
<link rel="help" href="http://www.w3.org/TR/css-writing-modes-3/#vertical-layout" title="7.1 Principles of Layout in Vertical Writing Modes">
<style type="text/css">
body {
margin: 0;
}
div.outer {
background: red url("right-bottom-300x300.png");
height: 300px;
width: 300px;
text-align: start;
writing-mode: vertical-rl;
direction: rtl;
}
div.inner {
display: inline-block;
background-color: green;
height: 100px;
width: 100px;
}
</style>
</head>
<body>
<div class="outer"><div class="inner"></div></div>
</body>
</html>

View File

@ -0,0 +1,20 @@
<!DOCTYPE html>
<html>
<head>
<title>CSS Reftest Reference</title>
<link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
<style type="text/css">
body {
margin: 0;
}
div {
position: absolute;
left: 0px;
top: 0px;
}
</style>
</head>
<body>
<div><img src="green-100x100.png" width="100" height="100" alt="Image download support must be enabled"></img></div>
</body>
</html>

View File

@ -0,0 +1,20 @@
<!DOCTYPE html>
<html>
<head>
<title>CSS Reftest Reference</title>
<link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/" />
<style type="text/css">
body {
margin: 0;
}
div {
position: absolute;
left: 200px;
top: 0px;
}
</style>
</head>
<body>
<div><img src="green-100x100.png" width="100" height="100" alt="Image download support must be enabled"></img></div>
</body>
</html>

View File

@ -0,0 +1,19 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>vertical bidi</title>
<style type="text/css">
div {
writing-mode: vertical-rl;
height: 150px;
width: 100px;
text-align: end;
background: yellow;
}
</style>
</head>
<body>
<div><b>ג bar</b> ב foo א</b></div>
</body>
</html>

View File

@ -0,0 +1,19 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>vertical bidi</title>
<style type="text/css">
div {
writing-mode: vertical-rl;
height: 150px;
width: 100px;
text-align: start;
background: yellow;
}
</style>
</head>
<body>
<div dir="rtl">א foo ב <b>bar ג</b></div>
</body>
</html>

Some files were not shown because too many files have changed in this diff Show More