зеркало из https://github.com/mozilla/gecko-dev.git
Bug 562169. Add support for :dir(ltr/rtl) CSS selector, content part, r=bz
This commit is contained in:
Родитель
7b0bd7bf8b
Коммит
88f3b972df
|
@ -0,0 +1,55 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 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 DirectionalityUtils_h___
|
||||
#define DirectionalityUtils_h___
|
||||
|
||||
class nsIContent;
|
||||
class nsIDocument;
|
||||
class nsINode;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
class Element;
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
namespace directionality {
|
||||
|
||||
enum Directionality {
|
||||
eDir_NotSet = 0,
|
||||
eDir_RTL = 1,
|
||||
eDir_LTR = 2
|
||||
};
|
||||
|
||||
/**
|
||||
* Set the directionality of an element according to the algorithm defined at
|
||||
* http://www.whatwg.org/specs/web-apps/current-work/multipage/elements.html#the-directionality,
|
||||
* not including elements with auto direction.
|
||||
*
|
||||
* @return the directionality that the element was set to
|
||||
*/
|
||||
Directionality RecomputeDirectionality(mozilla::dom::Element* aElement,
|
||||
bool aNotify = true);
|
||||
|
||||
/**
|
||||
* Set the directionality of any descendants of a node that do not themselves
|
||||
* have a dir attribute.
|
||||
* For performance reasons we walk down the descendant tree in the rare case
|
||||
* of setting the dir attribute, rather than walking up the ancestor tree in
|
||||
* the much more common case of getting the element's directionality.
|
||||
*/
|
||||
void SetDirectionalityOnDescendants(mozilla::dom::Element* aElement,
|
||||
Directionality aDir,
|
||||
bool aNotify = true);
|
||||
|
||||
} // end namespace directionality
|
||||
|
||||
} // end namespace mozilla
|
||||
|
||||
#endif /* DirectionalityUtils_h___ */
|
|
@ -10,6 +10,7 @@
|
|||
#include "mozilla/dom/FragmentOrElement.h" // for base class
|
||||
#include "nsChangeHint.h" // for enum
|
||||
#include "nsEventStates.h" // for member
|
||||
#include "mozilla/dom/DirectionalityUtils.h"
|
||||
|
||||
class nsEventStateManager;
|
||||
class nsFocusManager;
|
||||
|
@ -216,6 +217,54 @@ public:
|
|||
*/
|
||||
virtual nsIAtom *GetClassAttributeName() const = 0;
|
||||
|
||||
inline mozilla::directionality::Directionality GetDirectionality() const {
|
||||
if (HasFlag(NODE_HAS_DIRECTION_RTL)) {
|
||||
return mozilla::directionality::eDir_RTL;
|
||||
}
|
||||
|
||||
if (HasFlag(NODE_HAS_DIRECTION_LTR)) {
|
||||
return mozilla::directionality::eDir_LTR;
|
||||
}
|
||||
|
||||
return mozilla::directionality::eDir_NotSet;
|
||||
}
|
||||
|
||||
inline void SetDirectionality(mozilla::directionality::Directionality aDir,
|
||||
bool aNotify) {
|
||||
UnsetFlags(NODE_ALL_DIRECTION_FLAGS);
|
||||
if (!aNotify) {
|
||||
RemoveStatesSilently(DIRECTION_STATES);
|
||||
}
|
||||
|
||||
switch (aDir) {
|
||||
case (mozilla::directionality::eDir_RTL):
|
||||
SetFlags(NODE_HAS_DIRECTION_RTL);
|
||||
if (!aNotify) {
|
||||
AddStatesSilently(NS_EVENT_STATE_RTL);
|
||||
}
|
||||
break;
|
||||
|
||||
case(mozilla::directionality::eDir_LTR):
|
||||
SetFlags(NODE_HAS_DIRECTION_LTR);
|
||||
if (!aNotify) {
|
||||
AddStatesSilently(NS_EVENT_STATE_LTR);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Only call UpdateState if we need to notify, because we call
|
||||
* SetDirectionality for every element, and UpdateState is very very slow
|
||||
* for some elements.
|
||||
*/
|
||||
if (aNotify) {
|
||||
UpdateState(true);
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Method to get the _intrinsic_ content state of this element. This is the
|
||||
|
|
|
@ -48,6 +48,7 @@ $(NULL)
|
|||
EXPORTS_NAMESPACES = mozilla/dom mozilla
|
||||
|
||||
EXPORTS_mozilla/dom = \
|
||||
DirectionalityUtils.h \
|
||||
Element.h \
|
||||
FragmentOrElement.h \
|
||||
FromParser.h \
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include "nsPIDOMWindow.h" // for use in inline functions
|
||||
#include "nsPropertyTable.h" // for member
|
||||
#include "nsTHashtable.h" // for member
|
||||
#include "mozilla/dom/DirectionalityUtils.h"
|
||||
|
||||
class imgIRequest;
|
||||
class nsAString;
|
||||
|
@ -397,6 +398,10 @@ public:
|
|||
{
|
||||
mBidiOptions = aBidiOptions;
|
||||
}
|
||||
|
||||
inline mozilla::directionality::Directionality GetDocumentDirectionality() {
|
||||
return mDirectionality;
|
||||
}
|
||||
|
||||
/**
|
||||
* Access HTTP header data (this may also get set from other
|
||||
|
@ -1853,6 +1858,9 @@ protected:
|
|||
// defined in nsBidiUtils.h
|
||||
PRUint32 mBidiOptions;
|
||||
|
||||
// The root directionality of this document.
|
||||
mozilla::directionality::Directionality mDirectionality;
|
||||
|
||||
nsCString mContentLanguage;
|
||||
private:
|
||||
nsCString mContentType;
|
||||
|
|
|
@ -145,8 +145,16 @@ enum {
|
|||
// Set if the node has had :hover selectors matched against it
|
||||
NODE_HAS_RELEVANT_HOVER_RULES = 0x00080000U,
|
||||
|
||||
// Set if the node has right-to-left directionality
|
||||
NODE_HAS_DIRECTION_RTL = 0x00100000U,
|
||||
|
||||
// Set if the node has left-to-right directionality
|
||||
NODE_HAS_DIRECTION_LTR = 0x00200000U,
|
||||
|
||||
NODE_ALL_DIRECTION_FLAGS = NODE_HAS_DIRECTION_LTR | NODE_HAS_DIRECTION_RTL,
|
||||
|
||||
// Remaining bits are node type specific.
|
||||
NODE_TYPE_SPECIFIC_BITS_OFFSET = 20
|
||||
NODE_TYPE_SPECIFIC_BITS_OFFSET = 22
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -1279,6 +1287,8 @@ private:
|
|||
NodeIsContent,
|
||||
// Set if the node has animations or transitions
|
||||
ElementHasAnimations,
|
||||
// Set if node has a dir attribute with a valid value (ltr or rtl)
|
||||
NodeHasValidDirAttribute,
|
||||
// Guard value
|
||||
BooleanFlagCount
|
||||
};
|
||||
|
@ -1346,6 +1356,9 @@ public:
|
|||
void ClearPointerLock() { ClearBoolFlag(ElementHasPointerLock); }
|
||||
bool MayHaveAnimations() { return GetBoolFlag(ElementHasAnimations); }
|
||||
void SetMayHaveAnimations() { SetBoolFlag(ElementHasAnimations); }
|
||||
void SetHasValidDir() { SetBoolFlag(NodeHasValidDirAttribute); }
|
||||
void ClearHasValidDir() { ClearBoolFlag(NodeHasValidDirAttribute); }
|
||||
bool HasValidDir() const { return GetBoolFlag(NodeHasValidDirAttribute); }
|
||||
protected:
|
||||
void SetParentIsContent(bool aValue) { SetBoolFlag(ParentIsContent, aValue); }
|
||||
void SetInDocument() { SetBoolFlag(IsInDocument); }
|
||||
|
|
|
@ -0,0 +1,78 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=2 sw=2 et tw=78: */
|
||||
/* 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 "mozilla/dom/DirectionalityUtils.h"
|
||||
#include "nsINode.h"
|
||||
#include "nsIContent.h"
|
||||
#include "nsIDocument.h"
|
||||
#include "mozilla/dom/Element.h"
|
||||
#include "nsIDOMNodeFilter.h"
|
||||
#include "nsTreeWalker.h"
|
||||
#include "nsIDOMHTMLDocument.h"
|
||||
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
namespace directionality {
|
||||
|
||||
typedef mozilla::dom::Element Element;
|
||||
|
||||
Directionality
|
||||
RecomputeDirectionality(Element* aElement, bool aNotify)
|
||||
{
|
||||
Directionality dir = eDir_LTR;
|
||||
|
||||
if (aElement->HasValidDir()) {
|
||||
dir = aElement->GetDirectionality();
|
||||
} else {
|
||||
Element* parent = aElement->GetElementParent();
|
||||
if (parent) {
|
||||
// If the element doesn't have an explicit dir attribute with a valid
|
||||
// value, the directionality is the same as the parent element (but
|
||||
// don't propagate the parent directionality if it isn't set yet).
|
||||
Directionality parentDir = parent->GetDirectionality();
|
||||
if (parentDir != eDir_NotSet) {
|
||||
dir = parentDir;
|
||||
}
|
||||
} else {
|
||||
// If there is no parent element, the directionality is the same as the
|
||||
// document direction.
|
||||
Directionality documentDir =
|
||||
aElement->OwnerDoc()->GetDocumentDirectionality();
|
||||
if (documentDir != eDir_NotSet) {
|
||||
dir = documentDir;
|
||||
}
|
||||
}
|
||||
|
||||
aElement->SetDirectionality(dir, aNotify);
|
||||
}
|
||||
return dir;
|
||||
}
|
||||
|
||||
void
|
||||
SetDirectionalityOnDescendants(Element* aElement, Directionality aDir,
|
||||
bool aNotify)
|
||||
{
|
||||
for (nsIContent* child = aElement->GetFirstChild(); child; ) {
|
||||
if (!child->IsElement()) {
|
||||
child = child->GetNextNode(aElement);
|
||||
continue;
|
||||
}
|
||||
|
||||
Element* element = child->AsElement();
|
||||
if (element->HasValidDir()) {
|
||||
child = child->GetNextNonChildNode(aElement);
|
||||
continue;
|
||||
}
|
||||
element->SetDirectionality(aDir, aNotify);
|
||||
child = child->GetNextNode(aElement);
|
||||
}
|
||||
}
|
||||
|
||||
} // end namespace directionality
|
||||
|
||||
} // end namespace mozilla
|
||||
|
|
@ -53,6 +53,7 @@ LOCAL_INCLUDES = \
|
|||
$(NULL)
|
||||
|
||||
CPPSRCS = \
|
||||
DirectionalityUtils.cpp \
|
||||
nsAtomListUtils.cpp \
|
||||
nsAttrAndChildArray.cpp \
|
||||
nsAttrValue.cpp \
|
||||
|
|
|
@ -91,6 +91,7 @@
|
|||
#include "nsXMLEventsManager.h"
|
||||
|
||||
#include "nsBidiUtils.h"
|
||||
#include "mozilla/dom/DirectionalityUtils.h"
|
||||
|
||||
#include "nsIDOMUserDataHandler.h"
|
||||
#include "nsIDOMXPathEvaluator.h"
|
||||
|
@ -170,6 +171,7 @@
|
|||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::dom;
|
||||
using namespace mozilla::directionality;
|
||||
|
||||
typedef nsTArray<Link*> LinkArray;
|
||||
|
||||
|
@ -1510,6 +1512,7 @@ nsIDocument::nsIDocument()
|
|||
mAllowDNSPrefetch(true),
|
||||
mIsBeingUsedAsImage(false),
|
||||
mHasLinksToUpdate(false),
|
||||
mDirectionality(eDir_LTR),
|
||||
mPartID(0)
|
||||
{
|
||||
SetInDocument();
|
||||
|
@ -5583,6 +5586,15 @@ nsDocument::SetDir(const nsAString& aDirection)
|
|||
// No presentation; just set it on ourselves
|
||||
SetBidiOptions(options);
|
||||
}
|
||||
Directionality dir = elt->mValue == IBMBIDI_TEXTDIRECTION_RTL ?
|
||||
eDir_RTL : eDir_LTR;
|
||||
SetDocumentDirectionality(dir);
|
||||
// Set the directionality of the root element and its descendants, if any
|
||||
Element* rootElement = GetRootElement();
|
||||
if (rootElement) {
|
||||
rootElement->SetDirectionality(dir, true);
|
||||
SetDirectionalityOnDescendants(rootElement, dir);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
|
|
@ -1048,6 +1048,12 @@ protected:
|
|||
nsIContent* GetFirstBaseNodeWithHref();
|
||||
nsresult SetFirstBaseNodeWithHref(nsIContent *node);
|
||||
|
||||
inline void
|
||||
SetDocumentDirectionality(mozilla::directionality::Directionality aDir)
|
||||
{
|
||||
mDirectionality = aDir;
|
||||
}
|
||||
|
||||
// Get the first <title> element with the given IsNodeOfType type, or
|
||||
// return null if there isn't one
|
||||
nsIContent* GetTitleContent(PRUint32 aNodeType);
|
||||
|
|
|
@ -51,6 +51,7 @@
|
|||
#include "nsIDOMMutationEvent.h"
|
||||
#include "nsMutationEvent.h"
|
||||
#include "nsNodeUtils.h"
|
||||
#include "mozilla/dom/DirectionalityUtils.h"
|
||||
#include "nsDocument.h"
|
||||
#include "nsAttrValueOrString.h"
|
||||
#ifdef MOZ_XUL
|
||||
|
@ -128,6 +129,7 @@
|
|||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::dom;
|
||||
using namespace mozilla::directionality;
|
||||
|
||||
nsEventStates
|
||||
Element::IntrinsicState() const
|
||||
|
@ -1358,6 +1360,13 @@ nsGenericElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
|
|||
SetSubtreeRootPointer(aParent->SubtreeRoot());
|
||||
}
|
||||
|
||||
// This has to be here, rather than in nsGenericHTMLElement::BindToTree,
|
||||
// because it has to happen after updating the parent pointer, but before
|
||||
// recursively binding the kids.
|
||||
if (IsHTML()) {
|
||||
RecomputeDirectionality(this, false);
|
||||
}
|
||||
|
||||
// If NODE_FORCE_XBL_BINDINGS was set we might have anonymous children
|
||||
// that also need to be told that they are moving.
|
||||
nsresult rv;
|
||||
|
@ -1543,6 +1552,13 @@ nsGenericElement::UnbindFromTree(bool aDeep, bool aNullParent)
|
|||
}
|
||||
}
|
||||
|
||||
// This has to be here, rather than in nsGenericHTMLElement::UnbindFromTree,
|
||||
// because it has to happen after unsetting the parent pointer, but before
|
||||
// recursively unbinding the kids.
|
||||
if (IsHTML()) {
|
||||
RecomputeDirectionality(this, false);
|
||||
}
|
||||
|
||||
if (aDeep) {
|
||||
// Do the kids. Don't call GetChildCount() here since that'll force
|
||||
// XUL to generate template children, which there is no need for since
|
||||
|
|
|
@ -270,6 +270,7 @@ GK_ATOM(dialog, "dialog")
|
|||
GK_ATOM(difference, "difference")
|
||||
GK_ATOM(digit, "digit")
|
||||
GK_ATOM(dir, "dir")
|
||||
GK_ATOM(directionality, "directionality")
|
||||
GK_ATOM(disableOutputEscaping, "disable-output-escaping")
|
||||
GK_ATOM(disabled, "disabled")
|
||||
GK_ATOM(display, "display")
|
||||
|
|
|
@ -53,6 +53,7 @@
|
|||
|
||||
#include "nsHTMLParts.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "mozilla/dom/DirectionalityUtils.h"
|
||||
#include "nsString.h"
|
||||
#include "nsUnicharUtils.h"
|
||||
#include "nsGkAtoms.h"
|
||||
|
@ -96,6 +97,7 @@
|
|||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::dom;
|
||||
using namespace mozilla::directionality;
|
||||
|
||||
class nsINodeInfo;
|
||||
class nsIDOMNodeList;
|
||||
|
@ -1687,6 +1689,24 @@ nsGenericHTMLElement::UpdateEditableState(bool aNotify)
|
|||
nsStyledElement::UpdateEditableState(aNotify);
|
||||
}
|
||||
|
||||
nsEventStates
|
||||
nsGenericHTMLElement::IntrinsicState() const
|
||||
{
|
||||
nsEventStates state = nsGenericHTMLElementBase::IntrinsicState();
|
||||
|
||||
if (GetDirectionality() == eDir_RTL) {
|
||||
state |= NS_EVENT_STATE_RTL;
|
||||
state &= ~NS_EVENT_STATE_LTR;
|
||||
} else { // at least for HTML, directionality is exclusively LTR or RTL
|
||||
NS_ASSERTION(GetDirectionality() == eDir_LTR,
|
||||
"HTML element's directionality must be either RTL or LTR");
|
||||
state |= NS_EVENT_STATE_LTR;
|
||||
state &= ~NS_EVENT_STATE_RTL;
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsGenericHTMLElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
|
||||
nsIContent* aBindingParent,
|
||||
|
@ -1889,6 +1909,20 @@ nsGenericHTMLElement::AfterSetAttr(PRInt32 aNamespaceID, nsIAtom* aName,
|
|||
else if (aNotify && aName == nsGkAtoms::spellcheck) {
|
||||
SyncEditorsOnSubtree(this);
|
||||
}
|
||||
else if (aName == nsGkAtoms::dir) {
|
||||
Directionality dir;
|
||||
if (aValue &&
|
||||
(aValue->Equals(nsGkAtoms::ltr, eIgnoreCase) ||
|
||||
aValue->Equals(nsGkAtoms::rtl, eIgnoreCase))) {
|
||||
SetHasValidDir();
|
||||
dir = aValue->Equals(nsGkAtoms::rtl, eIgnoreCase) ? eDir_RTL : eDir_LTR;
|
||||
SetDirectionality(dir, aNotify);
|
||||
} else {
|
||||
ClearHasValidDir();
|
||||
dir = RecomputeDirectionality(this, aNotify);
|
||||
}
|
||||
SetDirectionalityOnDescendants(this, dir, aNotify);
|
||||
}
|
||||
}
|
||||
|
||||
return nsGenericHTMLElementBase::AfterSetAttr(aNamespaceID, aName,
|
||||
|
|
|
@ -50,6 +50,7 @@ public:
|
|||
NS_ASSERTION(mNodeInfo->NamespaceID() == kNameSpaceID_XHTML,
|
||||
"Unexpected namespace");
|
||||
AddStatesSilently(NS_EVENT_STATE_LTR);
|
||||
SetFlags(NODE_HAS_DIRECTION_LTR);
|
||||
}
|
||||
|
||||
/** Typesafe, non-refcounting cast from nsIContent. Cheaper than QI. **/
|
||||
|
@ -203,6 +204,8 @@ public:
|
|||
|
||||
virtual void UpdateEditableState(bool aNotify);
|
||||
|
||||
virtual nsEventStates IntrinsicState() const;
|
||||
|
||||
// Helper for setting our editable flag and notifying
|
||||
void DoSetEditableFlag(bool aEditable, bool aNotify) {
|
||||
SetEditableFlag(aEditable);
|
||||
|
|
Загрузка…
Ссылка в новой задаче