Skip to content
Permalink
Browse files
-2011-05-17 Nikolas Zimmermann <nzimmermann@rim.com>
        Reviewed by Dirk Schulze.

        Refactor TextRun creation
        https://bugs.webkit.org/show_bug.cgi?id=60255

        Add constructTextRun() methods to RenderBlock/InlineTextBox and use it in various places in rendering/.
        The long-term goal is to remove the ugly eight parameters catch-it-all TextRun constructor, and
        replace it with explicit setters/getters. To avoid expanding dozens of callsites, when removing
        the catch-it-all constructor, these helper functions are introduced, which hide the details of
        creating a TextRun.

        Furthermore it will be used to remove the platform layering violation, that TextRun stores
        RenderObject pointers for the sake of SVG Fonts support, see bug 60254.

        No change in functionaliy, no new tests.

        * rendering/EllipsisBox.cpp:
        (WebCore::EllipsisBox::paint):
        (WebCore::EllipsisBox::selectionRect):
        (WebCore::EllipsisBox::paintSelection):
        * rendering/InlineTextBox.cpp:
        (WebCore::InlineTextBox::selectionRect):
        (WebCore::InlineTextBox::paint):
        (WebCore::InlineTextBox::paintSelection):
        (WebCore::InlineTextBox::paintCompositionBackground):
        (WebCore::InlineTextBox::paintSpellingOrGrammarMarker):
        (WebCore::InlineTextBox::paintTextMatchMarker):
        (WebCore::InlineTextBox::computeRectForReplacementMarker):
        (WebCore::InlineTextBox::offsetForPosition):
        (WebCore::InlineTextBox::positionForOffset):
        (WebCore::InlineTextBox::constructTextRun):
        * rendering/InlineTextBox.h:
        * rendering/RenderBlock.cpp:
        (WebCore::RenderBlock::constructTextRunAllowTrailingExpansion):
        * rendering/RenderBlock.h:
        * rendering/RenderEmbeddedObject.cpp:
        (WebCore::RenderEmbeddedObject::getReplacementTextGeometry):
        * rendering/RenderFileUploadControl.cpp:
        (WebCore::RenderFileUploadControl::paintObject):
        (WebCore::RenderFileUploadControl::computePreferredLogicalWidths):
        * rendering/RenderImage.cpp:
        (WebCore::RenderImage::setImageSizeForAltText):
        (WebCore::RenderImage::paintReplaced):
        * rendering/RenderListBox.cpp:
        (WebCore::RenderListBox::updateFromElement):
        * rendering/RenderTextControl.cpp:
        (WebCore::RenderTextControl::getAvgCharWidth):


Canonical link: https://commits.webkit.org/76384@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@86739 268f45cc-cd09-0410-ab3c-d52691b4dbfc
  • Loading branch information
Nikolas Zimmermann committed May 18, 2011
1 parent 788d55b commit ff8a7b9aab8d39c7511751580667ffb05fb6dc16
Showing 11 changed files with 162 additions and 62 deletions.
@@ -1,3 +1,53 @@
2011-05-17 Nikolas Zimmermann <nzimmermann@rim.com>

Reviewed by Dirk Schulze.

Refactor TextRun creation
https://bugs.webkit.org/show_bug.cgi?id=60255

Add constructTextRun() methods to RenderBlock/InlineTextBox and use it in various places in rendering/.
The long-term goal is to remove the ugly eight parameters catch-it-all TextRun constructor, and
replace it with explicit setters/getters. To avoid expanding dozens of callsites, when removing
the catch-it-all constructor, these helper functions are introduced, which hide the details of
creating a TextRun.

Furthermore it will be used to remove the platform layering violation, that TextRun stores
RenderObject pointers for the sake of SVG Fonts support, see bug 60254.

No change in functionaliy, no new tests.

* rendering/EllipsisBox.cpp:
(WebCore::EllipsisBox::paint):
(WebCore::EllipsisBox::selectionRect):
(WebCore::EllipsisBox::paintSelection):
* rendering/InlineTextBox.cpp:
(WebCore::InlineTextBox::selectionRect):
(WebCore::InlineTextBox::paint):
(WebCore::InlineTextBox::paintSelection):
(WebCore::InlineTextBox::paintCompositionBackground):
(WebCore::InlineTextBox::paintSpellingOrGrammarMarker):
(WebCore::InlineTextBox::paintTextMatchMarker):
(WebCore::InlineTextBox::computeRectForReplacementMarker):
(WebCore::InlineTextBox::offsetForPosition):
(WebCore::InlineTextBox::positionForOffset):
(WebCore::InlineTextBox::constructTextRun):
* rendering/InlineTextBox.h:
* rendering/RenderBlock.cpp:
(WebCore::RenderBlock::constructTextRunAllowTrailingExpansion):
* rendering/RenderBlock.h:
* rendering/RenderEmbeddedObject.cpp:
(WebCore::RenderEmbeddedObject::getReplacementTextGeometry):
* rendering/RenderFileUploadControl.cpp:
(WebCore::RenderFileUploadControl::paintObject):
(WebCore::RenderFileUploadControl::computePreferredLogicalWidths):
* rendering/RenderImage.cpp:
(WebCore::RenderImage::setImageSizeForAltText):
(WebCore::RenderImage::paintReplaced):
* rendering/RenderListBox.cpp:
(WebCore::RenderListBox::updateFromElement):
* rendering/RenderTextControl.cpp:
(WebCore::RenderTextControl::getAvgCharWidth):

2011-05-17 Jeremy Noble <jer.noble@apple.com>

Reviewed by Darin Adler.
@@ -24,6 +24,7 @@
#include "GraphicsContext.h"
#include "HitTestResult.h"
#include "PaintInfo.h"
#include "RenderBlock.h"
#include "RootInlineBox.h"
#include "TextRun.h"

@@ -52,9 +53,8 @@ void EllipsisBox::paint(PaintInfo& paintInfo, int tx, int ty, int lineTop, int l
context->setFillColor(foreground, style->colorSpace());
}

const String& str = m_str;
// FIXME: Why is this alwasy LTR?
context->drawText(style->font(), TextRun(str.characters(), str.length(), false, 0, 0, TextRun::AllowTrailingExpansion, LTR, style->visuallyOrdered()), IntPoint(m_x + tx, m_y + ty + style->fontMetrics().ascent()));
// FIXME: Why is this always LTR? Fix by passing correct text run flags below.
context->drawText(style->font(), RenderBlock::constructTextRunAllowTrailingExpansion(m_str, style), IntPoint(m_x + tx, m_y + ty + style->fontMetrics().ascent()));

// Restore the regular fill color.
if (textColor != context->fillColor())
@@ -75,9 +75,8 @@ IntRect EllipsisBox::selectionRect(int tx, int ty)
{
RenderStyle* style = m_renderer->style(m_firstLine);
const Font& f = style->font();
// FIXME: Why is this always LTR?
return enclosingIntRect(f.selectionRectForText(TextRun(m_str.characters(), m_str.length(), false, 0, 0, TextRun::AllowTrailingExpansion, LTR, style->visuallyOrdered()),
IntPoint(m_x + tx, m_y + ty + root()->selectionTop()), root()->selectionHeight()));
// FIXME: Why is this always LTR? Fix by passing correct text run flags below.
return enclosingIntRect(f.selectionRectForText(RenderBlock::constructTextRunAllowTrailingExpansion(m_str, style), IntPoint(m_x + tx, m_y + ty + root()->selectionTop()), root()->selectionHeight()));
}

void EllipsisBox::paintSelection(GraphicsContext* context, int tx, int ty, RenderStyle* style, const Font& font)
@@ -96,9 +95,8 @@ void EllipsisBox::paintSelection(GraphicsContext* context, int tx, int ty, Rende
int y = root()->selectionTop();
int h = root()->selectionHeight();
context->clip(IntRect(m_x + tx, y + ty, m_logicalWidth, h));
// FIXME: Why is this always LTR?
context->drawHighlightForText(font, TextRun(m_str.characters(), m_str.length(), false, 0, 0, TextRun::AllowTrailingExpansion, LTR, style->visuallyOrdered()),
IntPoint(m_x + tx, m_y + ty + y), h, c, style->colorSpace());
// FIXME: Why is this always LTR? Fix by passing correct text run flags below.
context->drawHighlightForText(font, RenderBlock::constructTextRunAllowTrailingExpansion(m_str, style), IntPoint(m_x + tx, m_y + ty + y), h, c, style->colorSpace());
}

bool EllipsisBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const IntPoint& pointInContainer, int tx, int ty, int lineTop, int lineBottom)
@@ -42,6 +42,7 @@
#include "RenderRubyText.h"
#include "RenderTheme.h"
#include "Text.h"
#include "TextRun.h"
#include "break_lines.h"
#include <wtf/AlwaysInline.h>

@@ -159,8 +160,6 @@ RenderObject::SelectionState InlineTextBox::selectionState()
return state;
}

typedef Vector<UChar, 256> BufferForAppendingHyphen;

static void adjustCharactersAndLengthForHyphen(BufferForAppendingHyphen& charactersWithHyphen, RenderStyle* style, const UChar*& characters, int& length)
{
const AtomicString& hyphenString = style->hyphenString();
@@ -185,16 +184,13 @@ IntRect InlineTextBox::selectionRect(int tx, int ty, int startPos, int endPos)
RenderStyle* styleToUse = textObj->style(m_firstLine);
const Font& f = styleToUse->font();

const UChar* characters = textObj->text()->characters() + m_start;
int len = m_len;
BufferForAppendingHyphen charactersWithHyphen;
if (ePos == len && hasHyphen()) {
adjustCharactersAndLengthForHyphen(charactersWithHyphen, styleToUse, characters, len);
ePos = len;
}
bool respectHyphen = ePos == m_len && hasHyphen();
TextRun textRun = constructTextRun(styleToUse, respectHyphen ? &charactersWithHyphen : 0);
if (respectHyphen)
endPos = textRun.length();

IntRect r = enclosingIntRect(f.selectionRectForText(TextRun(characters, len, textObj->allowTabs(), textPos(), m_expansion, expansionBehavior(), direction(), m_dirOverride),
FloatPoint(logicalLeft(), selTop), selHeight, sPos, ePos));
IntRect r = enclosingIntRect(f.selectionRectForText(textRun, FloatPoint(logicalLeft(), selTop), selHeight, sPos, ePos));

int logicalWidth = r.width();
if (r.x() > logicalRight())
@@ -647,10 +643,9 @@ void InlineTextBox::paint(PaintInfo& paintInfo, int tx, int ty, int /*lineTop*/,
combinedText->charactersToRender(m_start, characters, length);

BufferForAppendingHyphen charactersWithHyphen;
TextRun textRun = constructTextRun(styleToUse, characters, length, hasHyphen() ? &charactersWithHyphen : 0);
if (hasHyphen())
adjustCharactersAndLengthForHyphen(charactersWithHyphen, styleToUse, characters, length);

TextRun textRun(characters, length, textRenderer()->allowTabs(), textPos(), m_expansion, expansionBehavior(), direction(), m_dirOverride || styleToUse->visuallyOrdered());
length = textRun.length();

int sPos = 0;
int ePos = 0;
@@ -812,10 +807,10 @@ void InlineTextBox::paintSelection(GraphicsContext* context, const FloatPoint& b
const UChar* characters = textRenderer()->text()->characters() + m_start;

BufferForAppendingHyphen charactersWithHyphen;
if (ePos == length && hasHyphen()) {
adjustCharactersAndLengthForHyphen(charactersWithHyphen, style, characters, length);
ePos = length;
}
bool respectHyphen = ePos == length && hasHyphen();
TextRun textRun = constructTextRun(style, characters, length, respectHyphen ? &charactersWithHyphen : 0);
if (respectHyphen)
ePos = textRun.length();

int deltaY = renderer()->style()->isFlippedLinesWritingMode() ? selectionBottom() - logicalBottom() : logicalTop() - selectionTop();
int selHeight = selectionHeight();
@@ -827,9 +822,7 @@ void InlineTextBox::paintSelection(GraphicsContext* context, const FloatPoint& b
clipRect.setWidth(maxX - clipRect.x());
context->clip(clipRect);

context->drawHighlightForText(font, TextRun(characters, length, textRenderer()->allowTabs(), textPos(), m_expansion, expansionBehavior(),
direction(), m_dirOverride || style->visuallyOrdered()),
localOrigin, selHeight, c, style->colorSpace(), sPos, ePos);
context->drawHighlightForText(font, textRun, localOrigin, selHeight, c, style->colorSpace(), sPos, ePos);
}

void InlineTextBox::paintCompositionBackground(GraphicsContext* context, const FloatPoint& boxOrigin, RenderStyle* style, const Font& font, int startPos, int endPos)
@@ -850,9 +843,7 @@ void InlineTextBox::paintCompositionBackground(GraphicsContext* context, const F
int deltaY = renderer()->style()->isFlippedLinesWritingMode() ? selectionBottom() - logicalBottom() : logicalTop() - selectionTop();
int selHeight = selectionHeight();
FloatPoint localOrigin(boxOrigin.x(), boxOrigin.y() - deltaY);
context->drawHighlightForText(font, TextRun(textRenderer()->text()->characters() + m_start, m_len, textRenderer()->allowTabs(), textPos(), m_expansion, expansionBehavior(),
direction(), m_dirOverride || style->visuallyOrdered()),
localOrigin, selHeight, c, style->colorSpace(), sPos, ePos);
context->drawHighlightForText(font, constructTextRun(style), localOrigin, selHeight, c, style->colorSpace(), sPos, ePos);
}

#if PLATFORM(MAC)
@@ -1010,8 +1001,8 @@ void InlineTextBox::paintSpellingOrGrammarMarker(GraphicsContext* pt, const Floa
int deltaY = renderer()->style()->isFlippedLinesWritingMode() ? selectionBottom() - logicalBottom() : logicalTop() - selectionTop();
int selHeight = selectionHeight();
FloatPoint startPoint(boxOrigin.x(), boxOrigin.y() - deltaY);
TextRun run(textRenderer()->text()->characters() + m_start, m_len, textRenderer()->allowTabs(), textPos(), m_expansion, expansionBehavior(), direction(), m_dirOverride || style->visuallyOrdered());
TextRun run = constructTextRun(style);

// FIXME: Convert the document markers to float rects.
IntRect markerRect = enclosingIntRect(font.selectionRectForText(run, startPoint, selHeight, startPosition, endPosition));
start = markerRect.x() - startPoint.x();
@@ -1055,8 +1046,8 @@ void InlineTextBox::paintTextMatchMarker(GraphicsContext* pt, const FloatPoint&

int sPos = max(marker.startOffset - m_start, (unsigned)0);
int ePos = min(marker.endOffset - m_start, (unsigned)m_len);
TextRun run(textRenderer()->text()->characters() + m_start, m_len, textRenderer()->allowTabs(), textPos(), m_expansion, expansionBehavior(), direction(), m_dirOverride || style->visuallyOrdered());
TextRun run = constructTextRun(style);

// Always compute and store the rect associated with this marker. The computed rect is in absolute coordinates.
IntRect markerRect = enclosingIntRect(font.selectionRectForText(run, IntPoint(m_x, selectionTop()), selHeight, sPos, ePos));
markerRect = renderer()->localToAbsoluteQuad(FloatRect(markerRect)).enclosingBoundingBox();
@@ -1082,7 +1073,7 @@ void InlineTextBox::computeRectForReplacementMarker(const DocumentMarker& marker

int sPos = max(marker.startOffset - m_start, (unsigned)0);
int ePos = min(marker.endOffset - m_start, (unsigned)m_len);
TextRun run(textRenderer()->text()->characters() + m_start, m_len, textRenderer()->allowTabs(), textPos(), m_expansion, expansionBehavior(), direction(), m_dirOverride || style->visuallyOrdered());
TextRun run = constructTextRun(style);
IntPoint startPoint = IntPoint(m_x, y);

// Compute and store the rect associated with this marker.
@@ -1242,9 +1233,7 @@ int InlineTextBox::offsetForPosition(float lineOffset, bool includePartialGlyphs
RenderText* text = toRenderText(renderer());
RenderStyle* style = text->style(m_firstLine);
const Font* f = &style->font();
int offset = f->offsetForPosition(TextRun(textRenderer()->text()->characters() + m_start, m_len,
textRenderer()->allowTabs(), textPos(), m_expansion, expansionBehavior(), direction(), m_dirOverride || style->visuallyOrdered()),
lineOffset - logicalLeft(), includePartialGlyphs);
int offset = f->offsetForPosition(constructTextRun(style), lineOffset - logicalLeft(), includePartialGlyphs);
if (blockIsInOppositeDirection && (!offset || offset == m_len))
return !offset ? m_len : 0;
return offset;
@@ -1259,12 +1248,13 @@ float InlineTextBox::positionForOffset(int offset) const
return logicalLeft();

RenderText* text = toRenderText(renderer());
const Font& f = text->style(m_firstLine)->font();
RenderStyle* styleToUse = text->style(m_firstLine);
ASSERT(styleToUse);
const Font& f = 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 f.selectionRectForText(TextRun(text->text()->characters() + m_start, m_len, textRenderer()->allowTabs(), textPos(), m_expansion, expansionBehavior(), direction(), m_dirOverride),
IntPoint(logicalLeft(), 0), 0, from, to).maxX();
return f.selectionRectForText(constructTextRun(styleToUse), IntPoint(logicalLeft(), 0), 0, from, to).maxX();
}

bool InlineTextBox::containsCaretOffset(int offset) const
@@ -1291,6 +1281,31 @@ bool InlineTextBox::containsCaretOffset(int offset) const
return true;
}

TextRun InlineTextBox::constructTextRun(RenderStyle* style, BufferForAppendingHyphen* charactersWithHyphen) const
{
ASSERT(style);

RenderText* textRenderer = this->textRenderer();
ASSERT(textRenderer);
ASSERT(textRenderer->characters());

return constructTextRun(style, textRenderer->characters() + start(), len(), charactersWithHyphen);
}

TextRun InlineTextBox::constructTextRun(RenderStyle* style, const UChar* characters, int length, BufferForAppendingHyphen* charactersWithHyphen) const
{
ASSERT(style);

RenderText* textRenderer = this->textRenderer();
ASSERT(textRenderer);

if (charactersWithHyphen)
adjustCharactersAndLengthForHyphen(*charactersWithHyphen, style, characters, length);

// FIXME: Remove TextRuns all-in-one-constructor and use explicit setters here.
return TextRun(characters, length, textRenderer->allowTabs(), textPos(), expansion(), expansionBehavior(), direction(), m_dirOverride || style->visuallyOrdered());
}

#ifndef NDEBUG

const char* InlineTextBox::boxName() const
@@ -34,6 +34,7 @@ struct DocumentMarker;

const unsigned short cNoTruncation = USHRT_MAX;
const unsigned short cFullTruncation = USHRT_MAX - 1;
typedef Vector<UChar, 256> BufferForAppendingHyphen;

// Helper functions shared by InlineTextBox / SVGRootInlineBox
void updateGraphicsContext(GraphicsContext*, const Color& fillColor, const Color& strokeColor, float strokeThickness, ColorSpace);
@@ -98,6 +99,9 @@ class InlineTextBox : public InlineBox {
int selectionBottom();
int selectionHeight();

TextRun constructTextRun(RenderStyle*, BufferForAppendingHyphen* = 0) const;
TextRun constructTextRun(RenderStyle*, const UChar*, int length, BufferForAppendingHyphen* = 0) const;

public:
virtual IntRect calculateBoundaries() const { return IntRect(x(), y(), width(), height()); }

@@ -6316,6 +6316,27 @@ inline void RenderBlock::FloatingObjects::decreaseObjectsCount(FloatingObject::T
m_rightObjectsCount--;
}

TextRun RenderBlock::constructTextRunAllowTrailingExpansion(const UChar* characters, int length, RenderStyle* style, TextRunFlags flags)
{
ASSERT(style);

TextDirection textDirection = LTR;
bool directionalOverride = style->visuallyOrdered();
if (flags != DefaultTextRunFlags) {
if (flags & RespectDirection)
textDirection = style->direction();
if (flags & RespectDirectionOverride)
directionalOverride |= style->unicodeBidi() == Override;
}

// FIXME: Remove TextRuns all-in-one-constructor and use explicit setters here.
return TextRun(characters, length, false, 0, 0, TextRun::AllowTrailingExpansion, textDirection, directionalOverride);
}

TextRun RenderBlock::constructTextRunAllowTrailingExpansion(const String& string, RenderStyle* style, TextRunFlags flags)
{
return constructTextRunAllowTrailingExpansion(string.characters(), string.length(), style, flags);
}

#ifndef NDEBUG

@@ -55,6 +55,14 @@ typedef MidpointState<InlineIterator> LineMidpointState;

enum CaretType { CursorCaret, DragCaret };

enum TextRunFlag {
DefaultTextRunFlags = 0,
RespectDirection = 1 << 0,
RespectDirectionOverride = 1 << 1
};

typedef unsigned TextRunFlags;

class RenderBlock : public RenderBox {
public:
RenderBlock(Node*);
@@ -161,6 +169,9 @@ class RenderBlock : public RenderBox {

static void appendRunsForObject(BidiRunList<BidiRun>&, int start, int end, RenderObject*, InlineBidiResolver&);

static TextRun constructTextRunAllowTrailingExpansion(const String&, RenderStyle*, TextRunFlags = DefaultTextRunFlags);
static TextRun constructTextRunAllowTrailingExpansion(const UChar*, int length, RenderStyle*, TextRunFlags = DefaultTextRunFlags);

ColumnInfo* columnInfo() const;
int columnGap() const;

@@ -197,7 +197,7 @@ bool RenderEmbeddedObject::getReplacementTextGeometry(int tx, int ty, FloatRect&
font = Font(fontDescription, 0, 0);
font.update(0);

run = TextRun(m_replacementText.characters(), m_replacementText.length());
run = TextRun(m_replacementText);
textWidth = font.width(run);

replacementTextRect.setSize(FloatSize(textWidth + replacementTextRoundedRectLeftRightTextMargin * 2, replacementTextRoundedRectHeight));

0 comments on commit ff8a7b9

Please sign in to comment.