static CSSValueID determineTextDirection(DocumentFragment* vttRoot) { ASSERT(vttRoot); // Apply the Unicode Bidirectional Algorithm's Paragraph Level steps to the // concatenation of the values of each WebVTT Text Object in nodes, in a // pre-order, depth-first traversal, excluding WebVTT Ruby Text Objects and // their descendants. TextDirection textDirection = LTR; Node* node = NodeTraversal::next(*vttRoot); while (node) { ASSERT(node->isDescendantOf(vttRoot)); if (node->isTextNode()) { bool hasStrongDirectionality; textDirection = determineDirectionality(node->nodeValue(), hasStrongDirectionality); if (hasStrongDirectionality) break; } else if (node->isVTTElement()) { if (toVTTElement(node)->webVTTNodeType() == VTTNodeTypeRubyText) { node = NodeTraversal::nextSkippingChildren(*node); continue; } } node = NodeTraversal::next(*node); } return isLeftToRightDirection(textDirection) ? CSSValueLtr : CSSValueRtl; }
TextDirection HTMLElement::directionality(Node** strongDirectionalityTextNode) const { if (isHTMLInputElement(*this)) { HTMLInputElement* inputElement = toHTMLInputElement(const_cast<HTMLElement*>(this)); bool hasStrongDirectionality; TextDirection textDirection = determineDirectionality(inputElement->value(), &hasStrongDirectionality); if (strongDirectionalityTextNode) *strongDirectionalityTextNode = hasStrongDirectionality ? inputElement : 0; return textDirection; } Node* node = ComposedTreeTraversal::firstChild(*this); while (node) { // Skip bdi, script, style and text form controls. if (equalIgnoringCase(node->nodeName(), "bdi") || isHTMLScriptElement(*node) || isHTMLStyleElement(*node) || (node->isElementNode() && toElement(node)->isTextFormControl())) { node = ComposedTreeTraversal::nextSkippingChildren(*node, this); continue; } // Skip elements with valid dir attribute if (node->isElementNode()) { AtomicString dirAttributeValue = toElement(node)->fastGetAttribute(dirAttr); if (isValidDirAttribute(dirAttributeValue)) { node = ComposedTreeTraversal::nextSkippingChildren(*node, this); continue; } } if (node->isTextNode()) { bool hasStrongDirectionality; TextDirection textDirection = determineDirectionality(node->textContent(true), &hasStrongDirectionality); if (hasStrongDirectionality) { if (strongDirectionalityTextNode) *strongDirectionalityTextNode = node; return textDirection; } } node = ComposedTreeTraversal::next(*node, this); } if (strongDirectionalityTextNode) *strongDirectionalityTextNode = 0; return LTR; }
TextRun constructTextRun(const Font& font, const String& string, const ComputedStyle& style, TextRunFlags flags) { return constructTextRun(font, string, style, string.isEmpty() || string.is8Bit() ? LTR : determineDirectionality(string), flags); }
TextMetrics* CanvasRenderingContext2D::measureText(const String& text) { TextMetrics* metrics = TextMetrics::create(); // The style resolution required for fonts is not available in frame-less // documents. if (!canvas()->document().frame()) return metrics; canvas()->document().updateStyleAndLayoutTreeForNode(canvas()); const Font& font = accessFont(); const SimpleFontData* fontData = font.primaryFont(); DCHECK(fontData); if (!fontData) return metrics; TextDirection direction; if (state().getDirection() == CanvasRenderingContext2DState::DirectionInherit) direction = determineDirectionality(text); else direction = toTextDirection(state().getDirection(), canvas()); TextRun textRun(text, 0, 0, TextRun::AllowTrailingExpansion | TextRun::ForbidLeadingExpansion, direction, false); textRun.setNormalizeSpace(true); FloatRect textBounds = font.selectionRectForText( textRun, FloatPoint(), font.getFontDescription().computedSize(), 0, -1, true); // x direction metrics->setWidth(font.width(textRun)); metrics->setActualBoundingBoxLeft(-textBounds.x()); metrics->setActualBoundingBoxRight(textBounds.maxX()); // y direction const FontMetrics& fontMetrics = fontData->getFontMetrics(); const float ascent = fontMetrics.floatAscent(); const float descent = fontMetrics.floatDescent(); const float baselineY = getFontBaseline(fontMetrics); metrics->setFontBoundingBoxAscent(ascent - baselineY); metrics->setFontBoundingBoxDescent(descent + baselineY); metrics->setActualBoundingBoxAscent(-textBounds.y() - baselineY); metrics->setActualBoundingBoxDescent(textBounds.maxY() + baselineY); // Note : top/bottom and ascend/descend are currently the same, so there's no // difference between the EM box's top and bottom and the font's ascend and // descend metrics->setEmHeightAscent(0); metrics->setEmHeightDescent(0); metrics->setHangingBaseline(0.8f * ascent - baselineY); metrics->setAlphabeticBaseline(-baselineY); metrics->setIdeographicBaseline(-descent - baselineY); return metrics; }
static CSSValueID determineTextDirection(DocumentFragment* vttRoot) { DEFINE_STATIC_LOCAL(const String, rtTag, ("rt")); ASSERT(vttRoot); // Apply the Unicode Bidirectional Algorithm's Paragraph Level steps to the // concatenation of the values of each WebVTT Text Object in nodes, in a // pre-order, depth-first traversal, excluding WebVTT Ruby Text Objects and // their descendants. TextDirection textDirection = LTR; for (Node* node = vttRoot->firstChild(); node; node = NodeTraversal::next(*node, vttRoot)) { if (!node->isTextNode() || node->localName() == rtTag) continue; bool hasStrongDirectionality; textDirection = determineDirectionality(node->nodeValue(), hasStrongDirectionality); if (hasStrongDirectionality) break; } return isLeftToRightDirection(textDirection) ? CSSValueLtr : CSSValueRtl; }
TextRun constructTextRun(RenderObject* context, const Font& font, const String& string, RenderStyle* style, TextRun::ExpansionBehavior expansion, TextRunFlags flags) { bool hasStrongDirectionality; return constructTextRun(context, font, string, style, determineDirectionality(string, hasStrongDirectionality), expansion, flags); }