mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Merge inbound to m-c. a=merge
This commit is contained in:
commit
1dcbd6bfde
@ -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
|
||||
|
@ -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',
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
@ -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
|
@ -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(
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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");
|
||||
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
};
|
||||
|
@ -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);
|
||||
|
@ -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]
|
||||
|
@ -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 = [
|
||||
|
111
dom/requestsync/tests/test_runNow.html
Normal file
111
dom/requestsync/tests/test_runNow.html
Normal 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>
|
@ -41,6 +41,8 @@ interface RequestSyncTask {
|
||||
|
||||
Promise<void> setPolicy(RequestSyncTaskPolicyState aState,
|
||||
optional long ovewrittenMinInterval);
|
||||
|
||||
Promise<void> runNow();
|
||||
};
|
||||
|
||||
[NavigatorProperty="syncManager",
|
||||
|
@ -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
|
||||
|
@ -86,7 +86,6 @@ public:
|
||||
uint32_t mCMSMode;
|
||||
|
||||
uint8_t mChannels;
|
||||
bool mFrameHasNoAlpha;
|
||||
bool mFrameIsHidden;
|
||||
bool mDisablePremultipliedAlpha;
|
||||
|
||||
|
59
js/src/jit-test/tests/ion/scripted-getter-setter.js
Normal file
59
js/src/jit-test/tests/ion/scripted-getter-setter.js
Normal 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();
|
32
js/src/jit-test/tests/profiler/getter-setter-ic.js
Normal file
32
js/src/jit-test/tests/profiler/getter-setter-ic.js
Normal 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();
|
@ -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:
|
||||
//
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -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
|
||||
//
|
||||
|
@ -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
|
||||
//
|
||||
|
@ -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
|
||||
//
|
||||
|
@ -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
|
||||
//
|
||||
|
@ -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.
|
||||
|
21
js/src/tests/ecma_5/misc/getter-setter-outerize-this.js
Normal file
21
js/src/tests/ecma_5/misc/getter-setter-outerize-this.js
Normal 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);
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
||||
/**
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
########################################################################
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
|
@ -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)) {
|
||||
|
@ -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.SetInFirstLetter(true);
|
||||
ll.SetFirstLetterStyleOK(true);
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
|
@ -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()
|
||||
{
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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));
|
||||
|
@ -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
|
||||
|
@ -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>
|
15
layout/reftests/text-indent/text-indent-parent-dynamic.html
Normal file
15
layout/reftests/text-indent/text-indent-parent-dynamic.html
Normal 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>
|
@ -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>
|
@ -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>
|
@ -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>
|
@ -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>
|
@ -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>
|
@ -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>
|
@ -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>
|
@ -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>
|
@ -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>
|
@ -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>
|
@ -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>
|
@ -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>
|
@ -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>
|
@ -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>
|
@ -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>
|
@ -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>
|
@ -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>
|
@ -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>
|
@ -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>
|
@ -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>
|
@ -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>
|
@ -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>
|
@ -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>
|
@ -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>
|
@ -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>
|
@ -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>
|
@ -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>
|
@ -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>
|
@ -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>
|
@ -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>
|
@ -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>
|
@ -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>
|
@ -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>
|
@ -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>
|
20
layout/reftests/writing-mode/1127488-align-top-left-ref.html
Normal file
20
layout/reftests/writing-mode/1127488-align-top-left-ref.html
Normal 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>
|
@ -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>
|
19
layout/reftests/writing-mode/1131013-vertical-bidi-ref.html
Normal file
19
layout/reftests/writing-mode/1131013-vertical-bidi-ref.html
Normal 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>
|
19
layout/reftests/writing-mode/1131013-vertical-bidi.html
Normal file
19
layout/reftests/writing-mode/1131013-vertical-bidi.html
Normal 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
Loading…
Reference in New Issue
Block a user