LayoutUnit InlineTextBox::lineHeight() const { if (!isText() || !lineLayoutItem().parent()) return 0; if (lineLayoutItem().isBR()) return toLayoutBR(lineLayoutItem())->lineHeight(isFirstLineStyle()); if (parent()->lineLayoutItem() == lineLayoutItem().parent()) return parent()->lineHeight(); return LineLayoutBoxModel(lineLayoutItem().parent()).lineHeight(isFirstLineStyle(), isHorizontal() ? HorizontalLine : VerticalLine, PositionOnContainingLine); }
bool EllipsisBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, LayoutUnit lineTop, LayoutUnit lineBottom) { LayoutPoint adjustedLocation = accumulatedOffset + roundedLayoutPoint(topLeft()); // Hit test the markup box. if (InlineBox* markupBox = this->markupBox()) { RenderStyle* style = renderer().style(isFirstLineStyle()); LayoutUnit mtx = adjustedLocation.x() + m_logicalWidth - markupBox->x(); LayoutUnit mty = adjustedLocation.y() + style->fontMetrics().ascent() - (markupBox->y() + markupBox->renderer().style(isFirstLineStyle())->fontMetrics().ascent()); if (markupBox->nodeAtPoint(request, result, locationInContainer, LayoutPoint(mtx, mty), lineTop, lineBottom)) { renderer().updateHitTestResult(result, locationInContainer.point() - LayoutSize(mtx, mty)); return true; } } FloatPoint boxOrigin = locationIncludingFlipping(); boxOrigin.moveBy(accumulatedOffset); FloatRect boundsRect(boxOrigin, size()); if (visibleToHitTestRequest(request) && boundsRect.intersects(HitTestLocation::rectForPoint(locationInContainer.point(), 0, 0, 0, 0))) { renderer().updateHitTestResult(result, locationInContainer.point() - toLayoutSize(adjustedLocation)); if (!result.addNodeToRectBasedTestResult(renderer().node(), request, locationInContainer, boundsRect)) return true; } return false; }
void EllipsisBox::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset, LayoutUnit lineTop, LayoutUnit lineBottom) { GraphicsContext* context = paintInfo.context; RenderStyle* style = renderer().style(isFirstLineStyle()); const Font& font = style->font(); FloatPoint boxOrigin = locationIncludingFlipping(); boxOrigin.moveBy(FloatPoint(paintOffset)); if (!isHorizontal()) boxOrigin.move(0, -virtualLogicalHeight()); FloatRect boxRect(boxOrigin, LayoutSize(logicalWidth(), virtualLogicalHeight())); GraphicsContextStateSaver stateSaver(*context); if (!isHorizontal()) context->concatCTM(InlineTextBox::rotation(boxRect, InlineTextBox::Clockwise)); FloatPoint textOrigin(boxOrigin.x(), boxOrigin.y() + font.fontMetrics().ascent()); bool isPrinting = renderer().document().printing(); bool haveSelection = !isPrinting && paintInfo.phase != PaintPhaseTextClip && selectionState() != RenderObject::SelectionNone; if (haveSelection) paintSelection(context, boxOrigin, style, font); else if (paintInfo.phase == PaintPhaseSelection) return; TextPainter::Style textStyle = TextPainter::textPaintingStyle(renderer(), style, paintInfo.forceBlackText(), isPrinting); if (haveSelection) textStyle = TextPainter::selectionPaintingStyle(renderer(), true, paintInfo.forceBlackText(), isPrinting, textStyle); TextRun textRun = constructTextRun(&renderer(), font, m_str, style, TextRun::AllowTrailingExpansion); TextPainter textPainter(context, font, textRun, textOrigin, boxRect, isHorizontal()); textPainter.paint(0, m_str.length(), m_str.length(), textStyle); paintMarkupBox(paintInfo, paintOffset, lineTop, lineBottom, style); }
IntRect EllipsisBox::selectionRect() { RenderStyle* style = m_renderer->style(isFirstLineStyle()); const Font& font = style->font(); // FIXME: Why is this always LTR? Fix by passing correct text run flags below. return enclosingIntRect(font.selectionRectForText(RenderBlock::constructTextRun(renderer(), font, m_str, style, TextRun::AllowTrailingExpansion), IntPoint(x(), y() + root()->selectionTopAdjustedForPrecedingBlock()), root()->selectionHeightAdjustedForPrecedingBlock())); }
void EllipsisBox::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset, LayoutUnit lineTop, LayoutUnit lineBottom) { GraphicsContext* context = paintInfo.context; RenderStyle* style = m_renderer->style(isFirstLineStyle()); Color styleTextColor = style->visitedDependentColor(CSSPropertyWebkitTextFillColor); if (styleTextColor != context->fillColor()) context->setFillColor(styleTextColor, style->colorSpace()); Color textColor = styleTextColor; const Font& font = style->font(); if (selectionState() != RenderObject::SelectionNone) { paintSelection(context, paintOffset, style, font); // Select the correct color for painting the text. Color foreground = paintInfo.forceBlackText() ? Color::black : renderer()->selectionForegroundColor(); if (foreground.isValid() && foreground != styleTextColor) context->setFillColor(foreground, style->colorSpace()); } const ShadowData* shadow = style->textShadow(); bool hasShadow = shadow; if (hasShadow) { // FIXME: it would be better if we could get the shadows top-to-bottom from the style. Vector<const ShadowData*, 4> shadows; do { shadows.append(shadow); } while ((shadow = shadow->next())); DrawLooper drawLooper; drawLooper.addUnmodifiedContent(); for (int i = shadows.size() - 1; i >= 0; i--) { shadow = shadows[i]; int shadowX = isHorizontal() ? shadow->x() : shadow->y(); int shadowY = isHorizontal() ? shadow->y() : -shadow->x(); FloatSize offset(shadowX, shadowY); drawLooper.addShadow(offset, shadow->blur(), shadow->color(), DrawLooper::ShadowRespectsTransforms, DrawLooper::ShadowIgnoresAlpha); } context->setDrawLooper(drawLooper); } // FIXME: Why is this always LTR? Fix by passing correct text run flags below. FloatPoint boxOrigin(paintOffset); boxOrigin.move(x(), y()); FloatRect boxRect(boxOrigin, LayoutSize(logicalWidth(), logicalHeight())); FloatPoint textOrigin(boxOrigin.x(), boxOrigin.y() + style->fontMetrics().ascent()); TextRun textRun = RenderBlock::constructTextRun(renderer(), font, m_str, style, TextRun::AllowTrailingExpansion); TextRunPaintInfo textRunPaintInfo(textRun); textRunPaintInfo.bounds = boxRect; context->drawText(font, textRunPaintInfo, textOrigin); // Restore the regular fill color. if (styleTextColor != context->fillColor()) context->setFillColor(styleTextColor, style->colorSpace()); if (hasShadow) context->clearDrawLooper(); paintMarkupBox(paintInfo, paintOffset, lineTop, lineBottom, style); }
void EllipsisBox::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset, LayoutUnit lineTop, LayoutUnit lineBottom) { GraphicsContext* context = paintInfo.context; RenderStyle* style = renderer().style(isFirstLineStyle()); const Font& font = style->font(); FloatPoint boxOrigin = locationIncludingFlipping(); boxOrigin.moveBy(FloatPoint(paintOffset)); if (!isHorizontal()) boxOrigin.move(0, -virtualLogicalHeight()); FloatRect boxRect(boxOrigin, LayoutSize(logicalWidth(), virtualLogicalHeight())); GraphicsContextStateSaver stateSaver(*context); if (!isHorizontal()) context->concatCTM(InlineTextBox::rotation(boxRect, InlineTextBox::Clockwise)); FloatPoint textOrigin = FloatPoint(boxOrigin.x(), boxOrigin.y() + font.fontMetrics().ascent()); Color styleTextColor = renderer().resolveColor(style, CSSPropertyWebkitTextFillColor); if (styleTextColor != context->fillColor()) context->setFillColor(styleTextColor); if (selectionState() != RenderObject::SelectionNone) { paintSelection(context, boxOrigin, style, font); // Select the correct color for painting the text. Color foreground = paintInfo.forceBlackText() ? Color::black : renderer().selectionForegroundColor(); if (foreground != styleTextColor) context->setFillColor(foreground); } // Text shadows are disabled when printing. http://crbug.com/258321 const ShadowList* shadowList = context->printing() ? 0 : style->textShadow(); bool hasShadow = shadowList; if (hasShadow) { OwnPtr<DrawLooperBuilder> drawLooperBuilder = DrawLooperBuilder::create(); for (size_t i = shadowList->shadows().size(); i--; ) { const ShadowData& shadow = shadowList->shadows()[i]; float shadowX = isHorizontal() ? shadow.x() : shadow.y(); float shadowY = isHorizontal() ? shadow.y() : -shadow.x(); FloatSize offset(shadowX, shadowY); drawLooperBuilder->addShadow(offset, shadow.blur(), shadow.color(), DrawLooperBuilder::ShadowRespectsTransforms, DrawLooperBuilder::ShadowIgnoresAlpha); } drawLooperBuilder->addUnmodifiedContent(); context->setDrawLooper(drawLooperBuilder.release()); } TextRun textRun = RenderBlockFlow::constructTextRun(&renderer(), font, m_str, style, TextRun::AllowTrailingExpansion); TextRunPaintInfo textRunPaintInfo(textRun); textRunPaintInfo.bounds = boxRect; context->drawText(font, textRunPaintInfo, textOrigin); // Restore the regular fill color. if (styleTextColor != context->fillColor()) context->setFillColor(styleTextColor); if (hasShadow) context->clearDrawLooper(); paintMarkupBox(paintInfo, paintOffset, lineTop, lineBottom, style); }
LayoutRect InlineTextBox::localSelectionRect(int startPos, int endPos) const { int sPos = std::max(startPos - m_start, 0); int ePos = std::min(endPos - m_start, (int)m_len); if (sPos > ePos) return LayoutRect(); FontCachePurgePreventer fontCachePurgePreventer; LayoutUnit selTop = root().selectionTop(); LayoutUnit selHeight = root().selectionHeight(); const ComputedStyle& styleToUse = lineLayoutItem().styleRef(isFirstLineStyle()); const Font& font = styleToUse.font(); StringBuilder charactersWithHyphen; bool respectHyphen = ePos == m_len && hasHyphen(); TextRun textRun = constructTextRun(styleToUse, font, respectHyphen ? &charactersWithHyphen : 0); LayoutPoint startingPoint = LayoutPoint(logicalLeft(), selTop); LayoutRect r; if (sPos || ePos != static_cast<int>(m_len)) { r = LayoutRect(enclosingIntRect(font.selectionRectForText(textRun, FloatPoint(startingPoint), selHeight, sPos, ePos))); } else { // Avoid computing the font width when the entire line box is selected as an optimization. // FIXME: the call to rawValue() below is temporary and should be removed once the transition // to LayoutUnit-based types is complete (crbug.com/321237) r = LayoutRect(enclosingIntRect(LayoutRect(startingPoint, LayoutSize(m_logicalWidth, selHeight)))); } LayoutUnit logicalWidth = r.width(); if (r.x() > logicalRight()) logicalWidth = 0; else if (r.maxX() > logicalRight()) logicalWidth = logicalRight() - r.x(); LayoutPoint topPoint; LayoutUnit width; LayoutUnit height; if (isHorizontal()) { topPoint = LayoutPoint(r.x(), selTop); width = logicalWidth; height = selHeight; if (hasWrappedSelectionNewline()) { if (!isLeftToRightDirection()) topPoint.setX(topPoint.x() - newlineSpaceWidth()); width += newlineSpaceWidth(); } } else { topPoint = LayoutPoint(selTop, r.x()); width = selHeight; height = logicalWidth; // TODO(wkorman): RTL text embedded in top-to-bottom text can create // bottom-to-top situations. Add tests and ensure we handle correctly. if (hasWrappedSelectionNewline()) height += newlineSpaceWidth(); } return LayoutRect(topPoint, LayoutSize(width, height)); }
LayoutUnit InlineBox::logicalHeight() const { if (hasVirtualLogicalHeight()) return virtualLogicalHeight(); if (lineLayoutItem().isText()) return m_bitfields.isText() ? LayoutUnit(lineLayoutItem().style(isFirstLineStyle())->fontMetrics().height()) : LayoutUnit(); if (lineLayoutItem().isBox() && parent()) return isHorizontal() ? toLayoutBox(layoutObject()).size().height() : toLayoutBox(layoutObject()).size().width(); ASSERT(isInlineFlowBox()); LineLayoutBoxModel flowObject = boxModelObject(); const FontMetrics& fontMetrics = lineLayoutItem().style(isFirstLineStyle())->fontMetrics(); LayoutUnit result = fontMetrics.height(); if (parent()) result += flowObject.borderAndPaddingLogicalHeight(); return result; }
float InlineBox::logicalHeight() const { if (hasVirtualLogicalHeight()) return virtualLogicalHeight(); if (renderer()->isText()) return m_bitfields.isText() ? renderer()->style(isFirstLineStyle())->fontMetrics().height() : 0; if (renderer()->isBox() && parent()) return isHorizontal() ? toRenderBox(m_renderer)->height() : toRenderBox(m_renderer)->width(); ASSERT(isInlineFlowBox()); RenderBoxModelObject* flowObject = boxModelObject(); const FontMetrics& fontMetrics = renderer()->style(isFirstLineStyle())->fontMetrics(); float result = fontMetrics.height(); if (parent()) result += flowObject->borderAndPaddingLogicalHeight(); return result; }
int InlineTextBox::baselinePosition(FontBaseline baselineType) const { if (!isText() || !parent()) return 0; if (parent()->getLineLayoutItem() == getLineLayoutItem().parent()) return parent()->baselinePosition(baselineType); return LineLayoutBoxModel(getLineLayoutItem().parent()) .baselinePosition(baselineType, isFirstLineStyle(), isHorizontal() ? HorizontalLine : VerticalLine, PositionOnContainingLine); }
int InlineTextBox::offsetForPosition(LayoutUnit lineOffset, bool includePartialGlyphs) const { if (isLineBreak()) return 0; if (lineOffset - logicalLeft() > logicalWidth()) return isLeftToRightDirection() ? len() : 0; if (lineOffset - logicalLeft() < 0) return isLeftToRightDirection() ? 0 : len(); LineLayoutText text = lineLayoutItem(); const ComputedStyle& style = text.styleRef(isFirstLineStyle()); const Font& font = style.font(); return font.offsetForPosition(constructTextRun(style, font), (lineOffset - logicalLeft()).toFloat(), includePartialGlyphs); }
LayoutUnit InlineTextBox::positionForOffset(int offset) const { ASSERT(offset >= m_start); ASSERT(offset <= m_start + m_len); if (isLineBreak()) return logicalLeft(); LineLayoutText text = lineLayoutItem(); const ComputedStyle& styleToUse = text.styleRef(isFirstLineStyle()); const Font& font = styleToUse.font(); int from = !isLeftToRightDirection() ? offset - m_start : 0; int to = !isLeftToRightDirection() ? m_len : offset - m_start; // FIXME: Do we need to add rightBearing here? return font.selectionRectForText(constructTextRun(styleToUse, font), IntPoint(logicalLeft(), 0), 0, from, to).maxX(); }
void InlineTextBox::characterWidths(Vector<float>& widths) const { FontCachePurgePreventer fontCachePurgePreventer; const ComputedStyle& styleToUse = lineLayoutItem().styleRef(isFirstLineStyle()); const Font& font = styleToUse.font(); TextRun textRun = constructTextRun(styleToUse, font); SimpleShaper shaper(&font, textRun); float lastWidth = 0; widths.resize(m_len); for (unsigned i = 0; i < m_len; i++) { shaper.advance(i + 1); widths[i] = shaper.runWidthSoFar() - lastWidth; lastWidth = shaper.runWidthSoFar(); } }
void EllipsisBox::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset, LayoutUnit lineTop, LayoutUnit lineBottom) { GraphicsContext* context = paintInfo.context; RenderStyle* style = renderer().style(isFirstLineStyle()); const Font& font = style->font(); FloatPoint boxOrigin = locationIncludingFlipping(); boxOrigin.moveBy(FloatPoint(paintOffset)); FloatRect boxRect(boxOrigin, LayoutSize(logicalWidth(), virtualLogicalHeight())); GraphicsContextStateSaver stateSaver(*context); FloatPoint textOrigin = FloatPoint(boxOrigin.x(), boxOrigin.y() + font.fontMetrics().ascent()); Color styleTextColor = renderer().resolveColor(style, CSSPropertyWebkitTextFillColor); if (styleTextColor != context->fillColor()) context->setFillColor(styleTextColor); if (selectionState() != RenderObject::SelectionNone) { paintSelection(context, boxOrigin, style, font); // Select the correct color for painting the text. Color foreground = paintInfo.forceBlackText() ? Color::black : renderer().selectionForegroundColor(); if (foreground != styleTextColor) context->setFillColor(foreground); } const ShadowList* shadowList = style->textShadow(); bool hasShadow = shadowList; if (hasShadow) context->setDrawLooper(shadowList->createDrawLooper(DrawLooperBuilder::ShadowIgnoresAlpha)); TextRun textRun = constructTextRun(&renderer(), font, m_str, style, TextRun::AllowTrailingExpansion); TextRunPaintInfo textRunPaintInfo(textRun); textRunPaintInfo.bounds = boxRect; context->drawText(font, textRunPaintInfo, textOrigin); // Restore the regular fill color. if (styleTextColor != context->fillColor()) context->setFillColor(styleTextColor); if (hasShadow) context->clearDrawLooper(); paintMarkupBox(paintInfo, paintOffset, lineTop, lineBottom, style); }
void InlineTextBox::characterWidths(Vector<float>& widths) const { if (!m_len) return; FontCachePurgePreventer fontCachePurgePreventer; ASSERT(getLineLayoutItem().text()); const ComputedStyle& styleToUse = getLineLayoutItem().styleRef(isFirstLineStyle()); const Font& font = styleToUse.font(); TextRun textRun = constructTextRun(styleToUse); Vector<CharacterRange> ranges = font.individualCharacterRanges(textRun); DCHECK_EQ(ranges.size(), m_len); widths.resize(ranges.size()); for (unsigned i = 0; i < ranges.size(); i++) widths[i] = ranges[i].width(); }
void InlineTextBox::characterWidths(Vector<float>& widths) const { if (!m_len) return; FontCachePurgePreventer fontCachePurgePreventer; ASSERT(getLineLayoutItem().text()); const ComputedStyle& styleToUse = getLineLayoutItem().styleRef(isFirstLineStyle()); const Font& font = styleToUse.font(); float lastWidth = 0; widths.resize(m_len); for (unsigned i = 0; i < m_len; i++) { StringView substringView = getLineLayoutItem().text().createView(); substringView.narrow(start(), 1 + i); TextRun textRun = constructTextRun(styleToUse, font, substringView, m_len); widths[i] = font.width(textRun, nullptr, nullptr) - lastWidth; lastWidth = font.width(textRun, nullptr, nullptr); } }
void EllipsisBox::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset, LayoutUnit lineTop, LayoutUnit lineBottom) { GraphicsContext* context = paintInfo.context; RenderStyle* style = renderer().style(isFirstLineStyle()); Color textColor = style->visitedDependentColor(CSSPropertyWebkitTextFillColor); if (textColor != context->fillColor()) context->setFillColor(textColor, style->colorSpace()); bool setShadow = false; if (style->textShadow()) { context->setShadow(LayoutSize(style->textShadow()->x(), style->textShadow()->y()), style->textShadow()->radius(), style->textShadow()->color(), style->colorSpace()); setShadow = true; } const Font& font = style->font(); if (selectionState() != RenderObject::SelectionNone) { paintSelection(context, paintOffset, style, font); // Select the correct color for painting the text. Color foreground = paintInfo.forceBlackText() ? Color::black : renderer().selectionForegroundColor(); if (foreground.isValid() && foreground != textColor) context->setFillColor(foreground, style->colorSpace()); } // FIXME: Why is this always LTR? Fix by passing correct text run flags below. context->drawText(font, RenderBlock::constructTextRun(&renderer(), font, m_str, style, TextRun::AllowTrailingExpansion), LayoutPoint(x() + paintOffset.x(), y() + paintOffset.y() + style->fontMetrics().ascent())); // Restore the regular fill color. if (textColor != context->fillColor()) context->setFillColor(textColor, style->colorSpace()); if (setShadow) context->clearShadow(); paintMarkupBox(paintInfo, paintOffset, lineTop, lineBottom, style); }
void EllipsisBox::paintMarkupBox(PaintInfo& paintInfo, const LayoutPoint& paintOffset, LayoutUnit lineTop, LayoutUnit lineBottom, RenderStyle* style) { InlineBox* markupBox = this->markupBox(); if (!markupBox) return; LayoutPoint adjustedPaintOffset = paintOffset; adjustedPaintOffset.move(x() + m_logicalWidth - markupBox->x(), y() + style->fontMetrics().ascent() - (markupBox->y() + markupBox->renderer().style(isFirstLineStyle())->fontMetrics().ascent())); markupBox->paint(paintInfo, adjustedPaintOffset, lineTop, lineBottom); }
IntRect EllipsisBox::selectionRect() const { const ComputedStyle& style = lineLayoutItem().styleRef(isFirstLineStyle()); const Font& font = style.font(); return enclosingIntRect(font.selectionRectForText(constructTextRun(font, m_str, style, TextRun::AllowTrailingExpansion), IntPoint(logicalLeft(), logicalTop() + root().selectionTopAdjustedForPrecedingBlock()), root().selectionHeightAdjustedForPrecedingBlock())); }
float InlineTextBox::newlineSpaceWidth() const { const ComputedStyle& styleToUse = lineLayoutItem().styleRef(isFirstLineStyle()); return styleToUse.font().spaceWidth(); }
IntRect EllipsisBox::selectionRect() { RenderStyle* style = renderer().style(isFirstLineStyle()); const Font& font = style->font(); return enclosingIntRect(font.selectionRectForText(constructTextRun(&renderer(), font, m_str, style, TextRun::AllowTrailingExpansion), IntPoint(logicalLeft(), logicalTop() + root().selectionTopAdjustedForPrecedingBlock()), root().selectionHeightAdjustedForPrecedingBlock())); }
LayoutUnit InlineTextBox::placeEllipsisBox(bool flowIsLTR, LayoutUnit visibleLeftEdge, LayoutUnit visibleRightEdge, LayoutUnit ellipsisWidth, LayoutUnit &truncatedWidth, bool& foundBox) { if (foundBox) { setTruncation(cFullTruncation); return -1; } // For LTR this is the left edge of the box, for RTL, the right edge in parent coordinates. LayoutUnit ellipsisX = flowIsLTR ? visibleRightEdge - ellipsisWidth : visibleLeftEdge + ellipsisWidth; // Criteria for full truncation: // LTR: the left edge of the ellipsis is to the left of our text run. // RTL: the right edge of the ellipsis is to the right of our text run. bool ltrFullTruncation = flowIsLTR && ellipsisX <= logicalLeft(); bool rtlFullTruncation = !flowIsLTR && ellipsisX >= logicalLeft() + logicalWidth(); if (ltrFullTruncation || rtlFullTruncation) { // Too far. Just set full truncation, but return -1 and let the ellipsis just be placed at the edge of the box. setTruncation(cFullTruncation); foundBox = true; return -1; } bool ltrEllipsisWithinBox = flowIsLTR && (ellipsisX < logicalRight()); bool rtlEllipsisWithinBox = !flowIsLTR && (ellipsisX > logicalLeft()); if (ltrEllipsisWithinBox || rtlEllipsisWithinBox) { foundBox = true; // The inline box may have different directionality than it's parent. Since truncation // behavior depends both on both the parent and the inline block's directionality, we // must keep track of these separately. bool ltr = isLeftToRightDirection(); if (ltr != flowIsLTR) { // Width in pixels of the visible portion of the box, excluding the ellipsis. int visibleBoxWidth = visibleRightEdge - visibleLeftEdge - ellipsisWidth; ellipsisX = ltr ? logicalLeft() + visibleBoxWidth : logicalRight() - visibleBoxWidth; } int offset = offsetForPosition(ellipsisX, false); if (offset == 0) { // No characters should be laid out. Set ourselves to full truncation and place the ellipsis at the min of our start // and the ellipsis edge. setTruncation(cFullTruncation); truncatedWidth += ellipsisWidth; return std::min(ellipsisX, logicalLeft()); } // Set the truncation index on the text run. setTruncation(offset); // If we got here that means that we were only partially truncated and we need to return the pixel offset at which // to place the ellipsis. LayoutUnit widthOfVisibleText = lineLayoutItem().width(m_start, offset, textPos(), flowIsLTR ? LTR : RTL, isFirstLineStyle()); // The ellipsis needs to be placed just after the last visible character. // Where "after" is defined by the flow directionality, not the inline // box directionality. // e.g. In the case of an LTR inline box truncated in an RTL flow then we can // have a situation such as |Hello| -> |...He| truncatedWidth += widthOfVisibleText + ellipsisWidth; if (flowIsLTR) return logicalLeft() + widthOfVisibleText; return logicalRight() - widthOfVisibleText - ellipsisWidth; } truncatedWidth += logicalWidth(); return -1; }