diff options
Diffstat (limited to 'Source/WebCore/html/HTMLElement.cpp')
-rw-r--r-- | Source/WebCore/html/HTMLElement.cpp | 155 |
1 files changed, 150 insertions, 5 deletions
diff --git a/Source/WebCore/html/HTMLElement.cpp b/Source/WebCore/html/HTMLElement.cpp index 22fc2f2..b3981c8 100644 --- a/Source/WebCore/html/HTMLElement.cpp +++ b/Source/WebCore/html/HTMLElement.cpp @@ -124,7 +124,7 @@ bool HTMLElement::mapToEntry(const QualifiedName& attrName, MappedAttributeEntry } if (attrName == dirAttr) { result = hasLocalName(bdoTag) ? eBDO : eUniversal; - return false; + return true; } return StyledElement::mapToEntry(attrName, result); @@ -148,14 +148,18 @@ void HTMLElement::parseMappedAttribute(Attribute* attr) } else if (attr->name() == tabindexAttr) { indexstring = getAttribute(tabindexAttr); int tabindex = 0; - if (parseHTMLInteger(indexstring, tabindex)) { + if (!indexstring.length()) { + clearTabIndexExplicitly(); + } else if (parseHTMLInteger(indexstring, tabindex)) { // Clamp tabindex to the range of 'short' to match Firefox's behavior. setTabIndexExplicitly(max(static_cast<int>(std::numeric_limits<short>::min()), min(tabindex, static_cast<int>(std::numeric_limits<short>::max())))); } } else if (attr->name() == langAttr) { // FIXME: Implement } else if (attr->name() == dirAttr) { - addCSSProperty(attr, CSSPropertyDirection, attr->value()); + if (!equalIgnoringCase(attr->value(), "auto")) + addCSSProperty(attr, CSSPropertyDirection, attr->value()); + dirAttributeChanged(attr); addCSSProperty(attr, CSSPropertyUnicodeBidi, hasLocalName(bdoTag) ? CSSValueBidiOverride : CSSValueEmbed); } else if (attr->name() == draggableAttr) { const AtomicString& value = attr->value(); @@ -655,7 +659,7 @@ bool HTMLElement::supportsFocus() const bool HTMLElement::isContentEditable() const { - if (document()->frame() && document()->frame()->isContentEditable()) + if (document()->inDesignMode()) return true; // Ideally we'd call ASSERT!needsStyleRecalc()) here, but @@ -674,7 +678,7 @@ bool HTMLElement::isContentEditable() const bool HTMLElement::isContentRichlyEditable() const { - if (document()->frame() && document()->frame()->isContentEditable()) + if (document()->inDesignMode()) return true; if (!renderer()) { @@ -878,6 +882,147 @@ void HTMLElement::dispatchInputEvents() ownerForm->dispatchFormInput(); } +static void setHasDirAutoFlagRecursively(Node* firstNode, bool flag, Node* lastNode = 0) +{ + firstNode->setSelfOrAncestorHasDirAutoAttribute(flag); + + Node* node = firstNode->firstChild(); + + while (node) { + if (node->selfOrAncestorHasDirAutoAttribute() == flag) + return; + + if (node->isHTMLElement() && toElement(node)->hasAttribute(dirAttr)) { + if (node == lastNode) + return; + node = node->traverseNextSibling(firstNode); + continue; + } + node->setSelfOrAncestorHasDirAutoAttribute(flag); + if (node == lastNode) + return; + node = node->traverseNextNode(firstNode); + } +} + +void HTMLElement::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta) +{ + StyledElement::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta); + adjustDirectionalityIfNeededAfterChildrenChanged(beforeChange, childCountDelta); +} + +TextDirection HTMLElement::directionalityIfhasDirAutoAttribute(bool& isAuto) const +{ + if (!(selfOrAncestorHasDirAutoAttribute() && equalIgnoringCase(getAttribute(dirAttr), "auto"))) { + isAuto = false; + return LTR; + } + + isAuto = true; + return directionality(); +} + +TextDirection HTMLElement::directionality(Node** strongDirectionalityTextNode) const +{ + Node* node = firstChild(); + while (node) { + // Skip bdi, script and style elements + if (equalIgnoringCase(node->nodeName(), "bdi") || node->hasTagName(scriptTag) || node->hasTagName(styleTag)) { + node = node->traverseNextSibling(this); + continue; + } + + // Skip elements with valid dir attribute + if (node->isElementNode()) { + AtomicString dirAttributeValue = toElement(node)->fastGetAttribute(dirAttr); + if (equalIgnoringCase(dirAttributeValue, "rtl") || equalIgnoringCase(dirAttributeValue, "ltr") || equalIgnoringCase(dirAttributeValue, "auto")) { + node = node->traverseNextSibling(this); + continue; + } + } + + if (node->isTextNode()) { + bool hasStrongDirectionality; + WTF::Unicode::Direction textDirection = node->textContent(true).defaultWritingDirection(&hasStrongDirectionality); + if (hasStrongDirectionality) { + if (strongDirectionalityTextNode) + *strongDirectionalityTextNode = node; + return (textDirection == WTF::Unicode::LeftToRight) ? LTR : RTL; + } + } + node = node->traverseNextNode(this); + } + if (strongDirectionalityTextNode) + *strongDirectionalityTextNode = 0; + return LTR; +} + +void HTMLElement::dirAttributeChanged(Attribute* attribute) +{ + Element* parent = parentElement(); + + if (parent && parent->isHTMLElement() && parent->selfOrAncestorHasDirAutoAttribute()) + toHTMLElement(parent)->adjustDirectionalityIfNeededAfterChildAttributeChanged(this); + + if (equalIgnoringCase(attribute->value(), "auto")) + calculateAndAdjustDirectionality(); +} + +void HTMLElement::adjustDirectionalityIfNeededAfterChildAttributeChanged(Element* child) +{ + ASSERT(selfOrAncestorHasDirAutoAttribute()); + Node* strongDirectionalityTextNode; + TextDirection textDirection = directionality(&strongDirectionalityTextNode); + setHasDirAutoFlagRecursively(child, false); + if (renderer() && renderer()->style() && renderer()->style()->direction() != textDirection) { + Element* elementToAdjust = this; + for (; elementToAdjust; elementToAdjust = elementToAdjust->parentElement()) { + if (elementToAdjust->hasAttribute(dirAttr)) { + elementToAdjust->setNeedsStyleRecalc(); + return; + } + } + } +} + +void HTMLElement::calculateAndAdjustDirectionality() +{ + Node* strongDirectionalityTextNode; + TextDirection textDirection = directionality(&strongDirectionalityTextNode); + setHasDirAutoFlagRecursively(this, true, strongDirectionalityTextNode); + if (renderer() && renderer()->style() && renderer()->style()->direction() != textDirection) + setNeedsStyleRecalc(); +} + +void HTMLElement::adjustDirectionalityIfNeededAfterChildrenChanged(Node* beforeChange, int childCountDelta) +{ + if ((!document() || document()->renderer()) && childCountDelta < 0) { + Node* node = beforeChange ? beforeChange->traverseNextSibling() : 0; + for (int counter = 0; node && counter < childCountDelta; counter++, node = node->traverseNextSibling()) { + if (node->isElementNode() && toElement(node)->hasAttribute(dirAttr)) + continue; + + setHasDirAutoFlagRecursively(node, false); + } + } + + if (!selfOrAncestorHasDirAutoAttribute()) + return; + + Node* oldMarkedNode = beforeChange ? beforeChange->traverseNextSibling() : 0; + while (oldMarkedNode && oldMarkedNode->isHTMLElement() && toHTMLElement(oldMarkedNode)->hasAttribute(dirAttr)) + oldMarkedNode = oldMarkedNode->traverseNextSibling(this); + if (oldMarkedNode) + setHasDirAutoFlagRecursively(oldMarkedNode, false); + + for (Element* elementToAdjust = this; elementToAdjust; elementToAdjust = elementToAdjust->parentElement()) { + if (elementToAdjust->isHTMLElement() && elementToAdjust->hasAttribute(dirAttr)) { + toHTMLElement(elementToAdjust)->calculateAndAdjustDirectionality(); + return; + } + } +} + } // namespace WebCore #ifndef NDEBUG |