- add third_party src.
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / rendering / InlineTextBox.cpp
1 /*
2  * (C) 1999 Lars Knoll (knoll@kde.org)
3  * (C) 2000 Dirk Mueller (mueller@kde.org)
4  * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights reserved.
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public License
17  * along with this library; see the file COPYING.LIB.  If not, write to
18  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19  * Boston, MA 02110-1301, USA.
20  *
21  */
22
23 #include "config.h"
24 #include "core/rendering/InlineTextBox.h"
25
26 #include "core/dom/Document.h"
27 #include "core/dom/DocumentMarkerController.h"
28 #include "core/dom/RenderedDocumentMarker.h"
29 #include "core/dom/Text.h"
30 #include "core/editing/Editor.h"
31 #include "core/editing/InputMethodController.h"
32 #include "core/frame/Frame.h"
33 #include "core/page/Page.h"
34 #include "core/page/Settings.h"
35 #include "core/platform/graphics/FontCache.h"
36 #include "core/platform/graphics/GraphicsContextStateSaver.h"
37 #include "core/platform/graphics/WidthIterator.h"
38 #include "core/rendering/AbstractInlineTextBox.h"
39 #include "core/rendering/EllipsisBox.h"
40 #include "core/rendering/HitTestResult.h"
41 #include "core/rendering/PaintInfo.h"
42 #include "core/rendering/RenderBR.h"
43 #include "core/rendering/RenderBlock.h"
44 #include "core/rendering/RenderCombineText.h"
45 #include "core/rendering/RenderRubyRun.h"
46 #include "core/rendering/RenderRubyText.h"
47 #include "core/rendering/RenderTheme.h"
48 #include "core/rendering/style/ShadowList.h"
49 #include "core/rendering/svg/SVGTextRunRenderingContext.h"
50 #include "platform/graphics/DrawLooper.h"
51 #include "wtf/Vector.h"
52 #include "wtf/text/CString.h"
53 #include "wtf/text/StringBuilder.h"
54
55 using namespace std;
56
57 namespace WebCore {
58
59 struct SameSizeAsInlineTextBox : public InlineBox {
60     unsigned variables[1];
61     unsigned short variables2[2];
62     void* pointers[2];
63 };
64
65 COMPILE_ASSERT(sizeof(InlineTextBox) == sizeof(SameSizeAsInlineTextBox), InlineTextBox_should_stay_small);
66
67 typedef WTF::HashMap<const InlineTextBox*, LayoutRect> InlineTextBoxOverflowMap;
68 static InlineTextBoxOverflowMap* gTextBoxesWithOverflow;
69
70 static const int misspellingLineThickness = 3;
71
72 void InlineTextBox::destroy()
73 {
74     AbstractInlineTextBox::willDestroy(this);
75
76     if (!knownToHaveNoOverflow() && gTextBoxesWithOverflow)
77         gTextBoxesWithOverflow->remove(this);
78     InlineBox::destroy();
79 }
80
81 void InlineTextBox::markDirty(bool dirty)
82 {
83     if (dirty) {
84         m_len = 0;
85         m_start = 0;
86     }
87     InlineBox::markDirty(dirty);
88 }
89
90 LayoutRect InlineTextBox::logicalOverflowRect() const
91 {
92     if (knownToHaveNoOverflow() || !gTextBoxesWithOverflow)
93         return enclosingIntRect(logicalFrameRect());
94     return gTextBoxesWithOverflow->get(this);
95 }
96
97 void InlineTextBox::setLogicalOverflowRect(const LayoutRect& rect)
98 {
99     ASSERT(!knownToHaveNoOverflow());
100     if (!gTextBoxesWithOverflow)
101         gTextBoxesWithOverflow = new InlineTextBoxOverflowMap;
102     gTextBoxesWithOverflow->add(this, rect);
103 }
104
105 int InlineTextBox::baselinePosition(FontBaseline baselineType) const
106 {
107     if (!isText() || !parent())
108         return 0;
109     if (parent()->renderer() == renderer()->parent())
110         return parent()->baselinePosition(baselineType);
111     return toRenderBoxModelObject(renderer()->parent())->baselinePosition(baselineType, isFirstLineStyle(), isHorizontal() ? HorizontalLine : VerticalLine, PositionOnContainingLine);
112 }
113
114 LayoutUnit InlineTextBox::lineHeight() const
115 {
116     if (!isText() || !renderer()->parent())
117         return 0;
118     if (m_renderer->isBR())
119         return toRenderBR(m_renderer)->lineHeight(isFirstLineStyle());
120     if (parent()->renderer() == renderer()->parent())
121         return parent()->lineHeight();
122     return toRenderBoxModelObject(renderer()->parent())->lineHeight(isFirstLineStyle(), isHorizontal() ? HorizontalLine : VerticalLine, PositionOnContainingLine);
123 }
124
125 LayoutUnit InlineTextBox::selectionTop()
126 {
127     return root()->selectionTop();
128 }
129
130 LayoutUnit InlineTextBox::selectionBottom()
131 {
132     return root()->selectionBottom();
133 }
134
135 LayoutUnit InlineTextBox::selectionHeight()
136 {
137     return root()->selectionHeight();
138 }
139
140 bool InlineTextBox::isSelected(int startPos, int endPos) const
141 {
142     int sPos = max(startPos - m_start, 0);
143     // The position after a hard line break is considered to be past its end.
144     // See the corresponding code in InlineTextBox::selectionState.
145     int ePos = min(endPos - m_start, int(m_len) + (isLineBreak() ? 0 : 1));
146     return (sPos < ePos);
147 }
148
149 RenderObject::SelectionState InlineTextBox::selectionState()
150 {
151     RenderObject::SelectionState state = renderer()->selectionState();
152     if (state == RenderObject::SelectionStart || state == RenderObject::SelectionEnd || state == RenderObject::SelectionBoth) {
153         int startPos, endPos;
154         renderer()->selectionStartEnd(startPos, endPos);
155         // The position after a hard line break is considered to be past its end.
156         // See the corresponding code in InlineTextBox::isSelected.
157         int lastSelectable = start() + len() - (isLineBreak() ? 1 : 0);
158
159         // FIXME: Remove -webkit-line-break: LineBreakAfterWhiteSpace.
160         int endOfLineAdjustmentForCSSLineBreak = renderer()->style()->lineBreak() == LineBreakAfterWhiteSpace ? -1 : 0;
161         bool start = (state != RenderObject::SelectionEnd && startPos >= m_start && startPos <= m_start + m_len + endOfLineAdjustmentForCSSLineBreak);
162         bool end = (state != RenderObject::SelectionStart && endPos > m_start && endPos <= lastSelectable);
163         if (start && end)
164             state = RenderObject::SelectionBoth;
165         else if (start)
166             state = RenderObject::SelectionStart;
167         else if (end)
168             state = RenderObject::SelectionEnd;
169         else if ((state == RenderObject::SelectionEnd || startPos < m_start) &&
170                  (state == RenderObject::SelectionStart || endPos > lastSelectable))
171             state = RenderObject::SelectionInside;
172         else if (state == RenderObject::SelectionBoth)
173             state = RenderObject::SelectionNone;
174     }
175
176     // If there are ellipsis following, make sure their selection is updated.
177     if (m_truncation != cNoTruncation && root()->ellipsisBox()) {
178         EllipsisBox* ellipsis = root()->ellipsisBox();
179         if (state != RenderObject::SelectionNone) {
180             int start, end;
181             selectionStartEnd(start, end);
182             // The ellipsis should be considered to be selected if the end of
183             // the selection is past the beginning of the truncation and the
184             // beginning of the selection is before or at the beginning of the
185             // truncation.
186             ellipsis->setSelectionState(end >= m_truncation && start <= m_truncation ?
187                 RenderObject::SelectionInside : RenderObject::SelectionNone);
188         } else
189             ellipsis->setSelectionState(RenderObject::SelectionNone);
190     }
191
192     return state;
193 }
194
195 LayoutRect InlineTextBox::localSelectionRect(int startPos, int endPos)
196 {
197     int sPos = max(startPos - m_start, 0);
198     int ePos = min(endPos - m_start, (int)m_len);
199
200     if (sPos > ePos)
201         return LayoutRect();
202
203     FontCachePurgePreventer fontCachePurgePreventer;
204
205     RenderText* textObj = textRenderer();
206     LayoutUnit selTop = selectionTop();
207     LayoutUnit selHeight = selectionHeight();
208     RenderStyle* styleToUse = textObj->style(isFirstLineStyle());
209     const Font& font = styleToUse->font();
210
211     StringBuilder charactersWithHyphen;
212     bool respectHyphen = ePos == m_len && hasHyphen();
213     TextRun textRun = constructTextRun(styleToUse, font, respectHyphen ? &charactersWithHyphen : 0);
214     if (respectHyphen)
215         endPos = textRun.length();
216
217     FloatPoint startingPoint = FloatPoint(logicalLeft(), selTop);
218     LayoutRect r;
219     if (sPos || ePos != static_cast<int>(m_len))
220         r = enclosingIntRect(font.selectionRectForText(textRun, startingPoint, selHeight, sPos, ePos));
221     else // Avoid computing the font width when the entire line box is selected as an optimization.
222         r = enclosingIntRect(FloatRect(startingPoint, FloatSize(m_logicalWidth, selHeight)));
223
224     LayoutUnit logicalWidth = r.width();
225     if (r.x() > logicalRight())
226         logicalWidth  = 0;
227     else if (r.maxX() > logicalRight())
228         logicalWidth = logicalRight() - r.x();
229
230     LayoutPoint topPoint = isHorizontal() ? LayoutPoint(r.x(), selTop) : LayoutPoint(selTop, r.x());
231     LayoutUnit width = isHorizontal() ? logicalWidth : selHeight;
232     LayoutUnit height = isHorizontal() ? selHeight : logicalWidth;
233
234     return LayoutRect(topPoint, LayoutSize(width, height));
235 }
236
237 void InlineTextBox::deleteLine()
238 {
239     toRenderText(renderer())->removeTextBox(this);
240     destroy();
241 }
242
243 void InlineTextBox::extractLine()
244 {
245     if (extracted())
246         return;
247
248     toRenderText(renderer())->extractTextBox(this);
249 }
250
251 void InlineTextBox::attachLine()
252 {
253     if (!extracted())
254         return;
255
256     toRenderText(renderer())->attachTextBox(this);
257 }
258
259 float InlineTextBox::placeEllipsisBox(bool flowIsLTR, float visibleLeftEdge, float visibleRightEdge, float ellipsisWidth, float &truncatedWidth, bool& foundBox)
260 {
261     if (foundBox) {
262         m_truncation = cFullTruncation;
263         return -1;
264     }
265
266     // For LTR this is the left edge of the box, for RTL, the right edge in parent coordinates.
267     float ellipsisX = flowIsLTR ? visibleRightEdge - ellipsisWidth : visibleLeftEdge + ellipsisWidth;
268
269     // Criteria for full truncation:
270     // LTR: the left edge of the ellipsis is to the left of our text run.
271     // RTL: the right edge of the ellipsis is to the right of our text run.
272     bool ltrFullTruncation = flowIsLTR && ellipsisX <= left();
273     bool rtlFullTruncation = !flowIsLTR && ellipsisX >= left() + logicalWidth();
274     if (ltrFullTruncation || rtlFullTruncation) {
275         // Too far.  Just set full truncation, but return -1 and let the ellipsis just be placed at the edge of the box.
276         m_truncation = cFullTruncation;
277         foundBox = true;
278         return -1;
279     }
280
281     bool ltrEllipsisWithinBox = flowIsLTR && (ellipsisX < right());
282     bool rtlEllipsisWithinBox = !flowIsLTR && (ellipsisX > left());
283     if (ltrEllipsisWithinBox || rtlEllipsisWithinBox) {
284         foundBox = true;
285
286         // The inline box may have different directionality than it's parent.  Since truncation
287         // behavior depends both on both the parent and the inline block's directionality, we
288         // must keep track of these separately.
289         bool ltr = isLeftToRightDirection();
290         if (ltr != flowIsLTR) {
291           // Width in pixels of the visible portion of the box, excluding the ellipsis.
292           int visibleBoxWidth = visibleRightEdge - visibleLeftEdge  - ellipsisWidth;
293           ellipsisX = ltr ? left() + visibleBoxWidth : right() - visibleBoxWidth;
294         }
295
296         int offset = offsetForPosition(ellipsisX, false);
297         if (offset == 0) {
298             // No characters should be rendered.  Set ourselves to full truncation and place the ellipsis at the min of our start
299             // and the ellipsis edge.
300             m_truncation = cFullTruncation;
301             truncatedWidth += ellipsisWidth;
302             return min(ellipsisX, x());
303         }
304
305         // Set the truncation index on the text run.
306         m_truncation = offset;
307
308         // If we got here that means that we were only partially truncated and we need to return the pixel offset at which
309         // to place the ellipsis.
310         float widthOfVisibleText = toRenderText(renderer())->width(m_start, offset, textPos(), isFirstLineStyle());
311
312         // The ellipsis needs to be placed just after the last visible character.
313         // Where "after" is defined by the flow directionality, not the inline
314         // box directionality.
315         // e.g. In the case of an LTR inline box truncated in an RTL flow then we can
316         // have a situation such as |Hello| -> |...He|
317         truncatedWidth += widthOfVisibleText + ellipsisWidth;
318         if (flowIsLTR)
319             return left() + widthOfVisibleText;
320         else
321             return right() - widthOfVisibleText - ellipsisWidth;
322     }
323     truncatedWidth += logicalWidth();
324     return -1;
325 }
326
327 Color correctedTextColor(Color textColor, Color backgroundColor)
328 {
329     // Adjust the text color if it is too close to the background color,
330     // by darkening or lightening it to move it further away.
331
332     int d = differenceSquared(textColor, backgroundColor);
333     // semi-arbitrarily chose 65025 (255^2) value here after a few tests;
334     if (d > 65025) {
335         return textColor;
336     }
337
338     int distanceFromWhite = differenceSquared(textColor, Color::white);
339     int distanceFromBlack = differenceSquared(textColor, Color::black);
340
341     if (distanceFromWhite < distanceFromBlack) {
342         return textColor.dark();
343     }
344
345     return textColor.light();
346 }
347
348 void updateGraphicsContext(GraphicsContext* context, const Color& fillColor, const Color& strokeColor, float strokeThickness)
349 {
350     TextDrawingModeFlags mode = context->textDrawingMode();
351     if (strokeThickness > 0) {
352         TextDrawingModeFlags newMode = mode | TextModeStroke;
353         if (mode != newMode) {
354             context->setTextDrawingMode(newMode);
355             mode = newMode;
356         }
357     }
358
359     if (mode & TextModeFill && fillColor != context->fillColor())
360         context->setFillColor(fillColor);
361
362     if (mode & TextModeStroke) {
363         if (strokeColor != context->strokeColor())
364             context->setStrokeColor(strokeColor);
365         if (strokeThickness != context->strokeThickness())
366             context->setStrokeThickness(strokeThickness);
367     }
368 }
369
370 bool InlineTextBox::isLineBreak() const
371 {
372     return renderer()->isBR() || (renderer()->style()->preserveNewline() && len() == 1 && (*textRenderer()->text().impl())[start()] == '\n');
373 }
374
375 bool InlineTextBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, LayoutUnit /* lineTop */, LayoutUnit /*lineBottom*/)
376 {
377     if (isLineBreak())
378         return false;
379
380     FloatPoint boxOrigin = locationIncludingFlipping();
381     boxOrigin.moveBy(accumulatedOffset);
382     FloatRect rect(boxOrigin, size());
383     if (m_truncation != cFullTruncation && visibleToHitTestRequest(request) && locationInContainer.intersects(rect)) {
384         renderer()->updateHitTestResult(result, flipForWritingMode(locationInContainer.point() - toLayoutSize(accumulatedOffset)));
385         if (!result.addNodeToRectBasedTestResult(renderer()->node(), request, locationInContainer, rect))
386             return true;
387     }
388     return false;
389 }
390
391 static void paintTextWithShadows(GraphicsContext* context,
392     const RenderObject* renderer, const Font& font, const TextRun& textRun,
393     const AtomicString& emphasisMark, int emphasisMarkOffset,
394     int startOffset, int endOffset, int truncationPoint,
395     const FloatPoint& textOrigin, const FloatRect& boxRect,
396     const ShadowList* shadowList, bool stroked, bool horizontal)
397 {
398     // Text shadows are disabled when printing. http://crbug.com/258321
399     bool hasShadow = shadowList && !context->printing();
400
401     if (hasShadow) {
402         DrawLooper drawLooper;
403         for (size_t i = shadowList->shadows().size(); i--; ) {
404             const ShadowData& shadow = shadowList->shadows()[i];
405             int shadowX = horizontal ? shadow.x() : shadow.y();
406             int shadowY = horizontal ? shadow.y() : -shadow.x();
407             FloatSize offset(shadowX, shadowY);
408             drawLooper.addShadow(offset, shadow.blur(), renderer->resolveColor(shadow.color()),
409                 DrawLooper::ShadowRespectsTransforms, DrawLooper::ShadowIgnoresAlpha);
410         }
411         drawLooper.addUnmodifiedContent();
412         context->setDrawLooper(drawLooper);
413     }
414
415     TextRunPaintInfo textRunPaintInfo(textRun);
416     textRunPaintInfo.bounds = boxRect;
417     if (startOffset <= endOffset) {
418         textRunPaintInfo.from = startOffset;
419         textRunPaintInfo.to = endOffset;
420         if (emphasisMark.isEmpty())
421             context->drawText(font, textRunPaintInfo, textOrigin);
422         else
423             context->drawEmphasisMarks(font, textRunPaintInfo, emphasisMark, textOrigin + IntSize(0, emphasisMarkOffset));
424     } else {
425         if (endOffset > 0) {
426             textRunPaintInfo.from = 0;
427             textRunPaintInfo.to = endOffset;
428             if (emphasisMark.isEmpty())
429                 context->drawText(font, textRunPaintInfo, textOrigin);
430             else
431                 context->drawEmphasisMarks(font, textRunPaintInfo, emphasisMark, textOrigin + IntSize(0, emphasisMarkOffset));
432         }
433         if (startOffset < truncationPoint) {
434             textRunPaintInfo.from = startOffset;
435             textRunPaintInfo.to = truncationPoint;
436             if (emphasisMark.isEmpty())
437                 context->drawText(font, textRunPaintInfo, textOrigin);
438             else
439                 context->drawEmphasisMarks(font, textRunPaintInfo, emphasisMark, textOrigin + IntSize(0, emphasisMarkOffset));
440         }
441     }
442
443     if (hasShadow)
444         context->clearDrawLooper();
445 }
446
447 bool InlineTextBox::getEmphasisMarkPosition(RenderStyle* style, TextEmphasisPosition& emphasisPosition) const
448 {
449     // This function returns true if there are text emphasis marks and they are suppressed by ruby text.
450     if (style->textEmphasisMark() == TextEmphasisMarkNone)
451         return false;
452
453     emphasisPosition = style->textEmphasisPosition();
454     if (emphasisPosition == TextEmphasisPositionUnder)
455         return true; // Ruby text is always over, so it cannot suppress emphasis marks under.
456
457     RenderBlock* containingBlock = renderer()->containingBlock();
458     if (!containingBlock->isRubyBase())
459         return true; // This text is not inside a ruby base, so it does not have ruby text over it.
460
461     if (!containingBlock->parent()->isRubyRun())
462         return true; // Cannot get the ruby text.
463
464     RenderRubyText* rubyText = toRenderRubyRun(containingBlock->parent())->rubyText();
465
466     // The emphasis marks over are suppressed only if there is a ruby text box and it not empty.
467     return !rubyText || !rubyText->firstLineBox();
468 }
469
470 enum RotationDirection { Counterclockwise, Clockwise };
471
472 static inline AffineTransform rotation(const FloatRect& boxRect, RotationDirection clockwise)
473 {
474     return clockwise ? AffineTransform(0, 1, -1, 0, boxRect.x() + boxRect.maxY(), boxRect.maxY() - boxRect.x())
475         : AffineTransform(0, -1, 1, 0, boxRect.x() - boxRect.maxY(), boxRect.x() + boxRect.maxY());
476 }
477
478 void InlineTextBox::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset, LayoutUnit /*lineTop*/, LayoutUnit /*lineBottom*/)
479 {
480     if (isLineBreak() || !paintInfo.shouldPaintWithinRoot(renderer()) || renderer()->style()->visibility() != VISIBLE ||
481         m_truncation == cFullTruncation || paintInfo.phase == PaintPhaseOutline || !m_len)
482         return;
483
484     ASSERT(paintInfo.phase != PaintPhaseSelfOutline && paintInfo.phase != PaintPhaseChildOutlines);
485
486     LayoutUnit logicalLeftSide = logicalLeftVisualOverflow();
487     LayoutUnit logicalRightSide = logicalRightVisualOverflow();
488     LayoutUnit logicalStart = logicalLeftSide + (isHorizontal() ? paintOffset.x() : paintOffset.y());
489     LayoutUnit logicalExtent = logicalRightSide - logicalLeftSide;
490
491     LayoutUnit paintEnd = isHorizontal() ? paintInfo.rect.maxX() : paintInfo.rect.maxY();
492     LayoutUnit paintStart = isHorizontal() ? paintInfo.rect.x() : paintInfo.rect.y();
493
494     LayoutPoint adjustedPaintOffset = roundedIntPoint(paintOffset);
495
496     if (logicalStart >= paintEnd || logicalStart + logicalExtent <= paintStart)
497         return;
498
499     bool isPrinting = textRenderer()->document().printing();
500
501     // Determine whether or not we're selected.
502     bool haveSelection = !isPrinting && paintInfo.phase != PaintPhaseTextClip && selectionState() != RenderObject::SelectionNone;
503     if (!haveSelection && paintInfo.phase == PaintPhaseSelection)
504         // When only painting the selection, don't bother to paint if there is none.
505         return;
506
507     if (m_truncation != cNoTruncation) {
508         if (renderer()->containingBlock()->style()->isLeftToRightDirection() != isLeftToRightDirection()) {
509             // Make the visible fragment of text hug the edge closest to the rest of the run by moving the origin
510             // at which we start drawing text.
511             // e.g. In the case of LTR text truncated in an RTL Context, the correct behavior is:
512             // |Hello|CBA| -> |...He|CBA|
513             // In order to draw the fragment "He" aligned to the right edge of it's box, we need to start drawing
514             // farther to the right.
515             // NOTE: WebKit's behavior differs from that of IE which appears to just overlay the ellipsis on top of the
516             // truncated string i.e.  |Hello|CBA| -> |...lo|CBA|
517             LayoutUnit widthOfVisibleText = toRenderText(renderer())->width(m_start, m_truncation, textPos(), isFirstLineStyle());
518             LayoutUnit widthOfHiddenText = m_logicalWidth - widthOfVisibleText;
519             // FIXME: The hit testing logic also needs to take this translation into account.
520             LayoutSize truncationOffset(isLeftToRightDirection() ? widthOfHiddenText : -widthOfHiddenText, 0);
521             adjustedPaintOffset.move(isHorizontal() ? truncationOffset : truncationOffset.transposedSize());
522         }
523     }
524
525     GraphicsContext* context = paintInfo.context;
526
527     RenderObject* rendererToUse = renderer();
528     RenderStyle* styleToUse = rendererToUse->style(isFirstLineStyle());
529
530     adjustedPaintOffset.move(0, styleToUse->isHorizontalWritingMode() ? 0 : -logicalHeight());
531
532     FloatPoint boxOrigin = locationIncludingFlipping();
533     boxOrigin.move(adjustedPaintOffset.x(), adjustedPaintOffset.y());
534     FloatRect boxRect(boxOrigin, LayoutSize(logicalWidth(), logicalHeight()));
535
536     RenderCombineText* combinedText = styleToUse->hasTextCombine() && textRenderer()->isCombineText() && toRenderCombineText(textRenderer())->isCombined() ? toRenderCombineText(textRenderer()) : 0;
537
538     bool shouldRotate = !isHorizontal() && !combinedText;
539     if (shouldRotate)
540         context->concatCTM(rotation(boxRect, Clockwise));
541
542     // Determine whether or not we have composition underlines to draw.
543     bool containsComposition = renderer()->node() && renderer()->frame()->inputMethodController().compositionNode() == renderer()->node();
544     bool useCustomUnderlines = containsComposition && renderer()->frame()->inputMethodController().compositionUsesCustomUnderlines();
545
546     // Determine the text colors and selection colors.
547     Color textFillColor;
548     Color textStrokeColor;
549     Color emphasisMarkColor;
550     float textStrokeWidth = styleToUse->textStrokeWidth();
551
552     // Text shadows are disabled when printing. http://crbug.com/258321
553     const ShadowList* textShadow = (context->printing() || paintInfo.forceBlackText()) ? 0 : styleToUse->textShadow();
554
555     if (paintInfo.forceBlackText()) {
556         textFillColor = Color::black;
557         textStrokeColor = Color::black;
558         emphasisMarkColor = Color::black;
559     } else {
560         textFillColor = rendererToUse->resolveColor(styleToUse, CSSPropertyWebkitTextFillColor);
561
562         bool forceBackgroundToWhite = false;
563         if (isPrinting) {
564             if (styleToUse->printColorAdjust() == PrintColorAdjustEconomy)
565                 forceBackgroundToWhite = true;
566             if (textRenderer()->document().settings() && textRenderer()->document().settings()->shouldPrintBackgrounds())
567                 forceBackgroundToWhite = false;
568         }
569
570         // Make the text fill color legible against a white background
571         if (forceBackgroundToWhite)
572             textFillColor = correctedTextColor(textFillColor, Color::white);
573
574         textStrokeColor = rendererToUse->resolveColor(styleToUse, CSSPropertyWebkitTextStrokeColor);
575
576         // Make the text stroke color legible against a white background
577         if (forceBackgroundToWhite)
578             textStrokeColor = correctedTextColor(textStrokeColor, Color::white);
579
580         emphasisMarkColor = rendererToUse->resolveColor(styleToUse, CSSPropertyWebkitTextEmphasisColor);
581
582         // Make the text stroke color legible against a white background
583         if (forceBackgroundToWhite)
584             emphasisMarkColor = correctedTextColor(emphasisMarkColor, Color::white);
585     }
586
587     bool paintSelectedTextOnly = (paintInfo.phase == PaintPhaseSelection);
588     bool paintSelectedTextSeparately = false;
589
590     Color selectionFillColor = textFillColor;
591     Color selectionStrokeColor = textStrokeColor;
592     Color selectionEmphasisMarkColor = emphasisMarkColor;
593     float selectionStrokeWidth = textStrokeWidth;
594     const ShadowList* selectionShadow = textShadow;
595     if (haveSelection) {
596         // Check foreground color first.
597         Color foreground = paintInfo.forceBlackText() ? Color::black : renderer()->selectionForegroundColor();
598         if (foreground.isValid() && foreground != selectionFillColor && foreground != Color::transparent) {
599             if (!paintSelectedTextOnly)
600                 paintSelectedTextSeparately = true;
601             selectionFillColor = foreground;
602         }
603
604         Color emphasisMarkForeground = paintInfo.forceBlackText() ? Color::black : renderer()->selectionEmphasisMarkColor();
605         if (emphasisMarkForeground.isValid() && emphasisMarkForeground != selectionEmphasisMarkColor) {
606             if (!paintSelectedTextOnly)
607                 paintSelectedTextSeparately = true;
608             selectionEmphasisMarkColor = emphasisMarkForeground;
609         }
610
611         if (RenderStyle* pseudoStyle = renderer()->getCachedPseudoStyle(SELECTION)) {
612             // Text shadows are disabled when printing. http://crbug.com/258321
613             const ShadowList* shadow = (context->printing() || paintInfo.forceBlackText()) ? 0 : pseudoStyle->textShadow();
614             if (shadow != selectionShadow) {
615                 if (!paintSelectedTextOnly)
616                     paintSelectedTextSeparately = true;
617                 selectionShadow = shadow;
618             }
619
620             float strokeWidth = pseudoStyle->textStrokeWidth();
621             if (strokeWidth != selectionStrokeWidth) {
622                 if (!paintSelectedTextOnly)
623                     paintSelectedTextSeparately = true;
624                 selectionStrokeWidth = strokeWidth;
625             }
626
627             Color stroke = paintInfo.forceBlackText() ? Color::black : rendererToUse->resolveColor(pseudoStyle, CSSPropertyWebkitTextStrokeColor);
628             if (stroke != selectionStrokeColor) {
629                 if (!paintSelectedTextOnly)
630                     paintSelectedTextSeparately = true;
631                 selectionStrokeColor = stroke;
632             }
633         }
634     }
635
636     // Set our font.
637     const Font& font = styleToUse->font();
638
639     FloatPoint textOrigin = FloatPoint(boxOrigin.x(), boxOrigin.y() + font.fontMetrics().ascent());
640
641     if (combinedText)
642         combinedText->adjustTextOrigin(textOrigin, boxRect);
643
644     // 1. Paint backgrounds behind text if needed. Examples of such backgrounds include selection
645     // and composition underlines.
646     if (paintInfo.phase != PaintPhaseSelection && paintInfo.phase != PaintPhaseTextClip && !isPrinting) {
647
648         if (containsComposition && !useCustomUnderlines) {
649             paintCompositionBackground(context, boxOrigin, styleToUse, font,
650                 renderer()->frame()->inputMethodController().compositionStart(),
651                 renderer()->frame()->inputMethodController().compositionEnd());
652         }
653
654         paintDocumentMarkers(context, boxOrigin, styleToUse, font, true);
655
656         if (haveSelection && !useCustomUnderlines)
657             paintSelection(context, boxOrigin, styleToUse, font, selectionFillColor);
658     }
659
660     // 2. Now paint the foreground, including text and decorations like underline/overline (in quirks mode only).
661     int length = m_len;
662     int maximumLength;
663     StringView string;
664     if (!combinedText) {
665         string = textRenderer()->text().createView();
666         if (static_cast<unsigned>(length) != string.length() || m_start)
667             string.narrow(m_start, length);
668         maximumLength = textRenderer()->textLength() - m_start;
669     } else {
670         combinedText->getStringToRender(m_start, string, length);
671         maximumLength = length;
672     }
673
674     StringBuilder charactersWithHyphen;
675     TextRun textRun = constructTextRun(styleToUse, font, string, maximumLength, hasHyphen() ? &charactersWithHyphen : 0);
676     if (hasHyphen())
677         length = textRun.length();
678
679     int sPos = 0;
680     int ePos = 0;
681     if (paintSelectedTextOnly || paintSelectedTextSeparately)
682         selectionStartEnd(sPos, ePos);
683
684     if (m_truncation != cNoTruncation) {
685         sPos = min<int>(sPos, m_truncation);
686         ePos = min<int>(ePos, m_truncation);
687         length = m_truncation;
688     }
689
690     int emphasisMarkOffset = 0;
691     TextEmphasisPosition emphasisMarkPosition;
692     bool hasTextEmphasis = getEmphasisMarkPosition(styleToUse, emphasisMarkPosition);
693     const AtomicString& emphasisMark = hasTextEmphasis ? styleToUse->textEmphasisMarkString() : nullAtom;
694     if (!emphasisMark.isEmpty())
695         emphasisMarkOffset = emphasisMarkPosition == TextEmphasisPositionOver ? -font.fontMetrics().ascent() - font.emphasisMarkDescent(emphasisMark) : font.fontMetrics().descent() + font.emphasisMarkAscent(emphasisMark);
696
697     if (!paintSelectedTextOnly) {
698         // For stroked painting, we have to change the text drawing mode.  It's probably dangerous to leave that mutated as a side
699         // effect, so only when we know we're stroking, do a save/restore.
700         GraphicsContextStateSaver stateSaver(*context, textStrokeWidth > 0);
701
702         updateGraphicsContext(context, textFillColor, textStrokeColor, textStrokeWidth);
703         if (!paintSelectedTextSeparately || ePos <= sPos) {
704             // FIXME: Truncate right-to-left text correctly.
705             paintTextWithShadows(context, rendererToUse, font, textRun, nullAtom, 0, 0, length, length, textOrigin, boxRect, textShadow, textStrokeWidth > 0, isHorizontal());
706         } else {
707             paintTextWithShadows(context, rendererToUse, font, textRun, nullAtom, 0, ePos, sPos, length, textOrigin, boxRect, textShadow, textStrokeWidth > 0, isHorizontal());
708         }
709
710         if (!emphasisMark.isEmpty()) {
711             updateGraphicsContext(context, emphasisMarkColor, textStrokeColor, textStrokeWidth);
712
713             DEFINE_STATIC_LOCAL(TextRun, objectReplacementCharacterTextRun, (&objectReplacementCharacter, 1));
714             TextRun& emphasisMarkTextRun = combinedText ? objectReplacementCharacterTextRun : textRun;
715             FloatPoint emphasisMarkTextOrigin = combinedText ? FloatPoint(boxOrigin.x() + boxRect.width() / 2, boxOrigin.y() + font.fontMetrics().ascent()) : textOrigin;
716             if (combinedText)
717                 context->concatCTM(rotation(boxRect, Clockwise));
718
719             if (!paintSelectedTextSeparately || ePos <= sPos) {
720                 // FIXME: Truncate right-to-left text correctly.
721                 paintTextWithShadows(context, rendererToUse, combinedText ? combinedText->originalFont() : font, emphasisMarkTextRun, emphasisMark, emphasisMarkOffset, 0, length, length, emphasisMarkTextOrigin, boxRect, textShadow, textStrokeWidth > 0, isHorizontal());
722             } else {
723                 paintTextWithShadows(context, rendererToUse, combinedText ? combinedText->originalFont() : font, emphasisMarkTextRun, emphasisMark, emphasisMarkOffset, ePos, sPos, length, emphasisMarkTextOrigin, boxRect, textShadow, textStrokeWidth > 0, isHorizontal());
724             }
725
726             if (combinedText)
727                 context->concatCTM(rotation(boxRect, Counterclockwise));
728         }
729     }
730
731     if ((paintSelectedTextOnly || paintSelectedTextSeparately) && sPos < ePos) {
732         // paint only the text that is selected
733         GraphicsContextStateSaver stateSaver(*context, selectionStrokeWidth > 0);
734
735         updateGraphicsContext(context, selectionFillColor, selectionStrokeColor, selectionStrokeWidth);
736         paintTextWithShadows(context, rendererToUse, font, textRun, nullAtom, 0, sPos, ePos, length, textOrigin, boxRect, selectionShadow, selectionStrokeWidth > 0, isHorizontal());
737         if (!emphasisMark.isEmpty()) {
738             updateGraphicsContext(context, selectionEmphasisMarkColor, textStrokeColor, textStrokeWidth);
739
740             DEFINE_STATIC_LOCAL(TextRun, objectReplacementCharacterTextRun, (&objectReplacementCharacter, 1));
741             TextRun& emphasisMarkTextRun = combinedText ? objectReplacementCharacterTextRun : textRun;
742             FloatPoint emphasisMarkTextOrigin = combinedText ? FloatPoint(boxOrigin.x() + boxRect.width() / 2, boxOrigin.y() + font.fontMetrics().ascent()) : textOrigin;
743             if (combinedText)
744                 context->concatCTM(rotation(boxRect, Clockwise));
745
746             paintTextWithShadows(context, rendererToUse, combinedText ? combinedText->originalFont() : font, emphasisMarkTextRun, emphasisMark, emphasisMarkOffset, sPos, ePos, length, emphasisMarkTextOrigin, boxRect, selectionShadow, selectionStrokeWidth > 0, isHorizontal());
747
748             if (combinedText)
749                 context->concatCTM(rotation(boxRect, Counterclockwise));
750         }
751     }
752
753     // Paint decorations
754     TextDecoration textDecorations = styleToUse->textDecorationsInEffect();
755     if (textDecorations != TextDecorationNone && paintInfo.phase != PaintPhaseSelection) {
756         updateGraphicsContext(context, textFillColor, textStrokeColor, textStrokeWidth);
757         if (combinedText)
758             context->concatCTM(rotation(boxRect, Clockwise));
759         paintDecoration(context, boxOrigin, textDecorations, styleToUse->textDecorationStyle(), textShadow);
760         if (combinedText)
761             context->concatCTM(rotation(boxRect, Counterclockwise));
762     }
763
764     if (paintInfo.phase == PaintPhaseForeground) {
765         paintDocumentMarkers(context, boxOrigin, styleToUse, font, false);
766
767         if (useCustomUnderlines) {
768             const Vector<CompositionUnderline>& underlines = renderer()->frame()->inputMethodController().customCompositionUnderlines();
769             size_t numUnderlines = underlines.size();
770
771             for (size_t index = 0; index < numUnderlines; ++index) {
772                 const CompositionUnderline& underline = underlines[index];
773
774                 if (underline.endOffset <= start())
775                     // underline is completely before this run.  This might be an underline that sits
776                     // before the first run we draw, or underlines that were within runs we skipped
777                     // due to truncation.
778                     continue;
779
780                 if (underline.startOffset <= end()) {
781                     // underline intersects this run.  Paint it.
782                     paintCompositionUnderline(context, boxOrigin, underline);
783                     if (underline.endOffset > end() + 1)
784                         // underline also runs into the next run. Bail now, no more marker advancement.
785                         break;
786                 } else
787                     // underline is completely after this run, bail.  A later run will paint it.
788                     break;
789             }
790         }
791     }
792
793     if (shouldRotate)
794         context->concatCTM(rotation(boxRect, Counterclockwise));
795 }
796
797 void InlineTextBox::selectionStartEnd(int& sPos, int& ePos)
798 {
799     int startPos, endPos;
800     if (renderer()->selectionState() == RenderObject::SelectionInside) {
801         startPos = 0;
802         endPos = textRenderer()->textLength();
803     } else {
804         textRenderer()->selectionStartEnd(startPos, endPos);
805         if (renderer()->selectionState() == RenderObject::SelectionStart)
806             endPos = textRenderer()->textLength();
807         else if (renderer()->selectionState() == RenderObject::SelectionEnd)
808             startPos = 0;
809     }
810
811     sPos = max(startPos - m_start, 0);
812     ePos = min(endPos - m_start, (int)m_len);
813 }
814
815 void alignSelectionRectToDevicePixels(FloatRect& rect)
816 {
817     float maxX = floorf(rect.maxX());
818     rect.setX(floorf(rect.x()));
819     rect.setWidth(roundf(maxX - rect.x()));
820 }
821
822 void InlineTextBox::paintSelection(GraphicsContext* context, const FloatPoint& boxOrigin, RenderStyle* style, const Font& font, Color textColor)
823 {
824     if (context->paintingDisabled())
825         return;
826
827     // See if we have a selection to paint at all.
828     int sPos, ePos;
829     selectionStartEnd(sPos, ePos);
830     if (sPos >= ePos)
831         return;
832
833     Color c = renderer()->selectionBackgroundColor();
834     if (!c.isValid() || !c.alpha())
835         return;
836
837     // If the text color ends up being the same as the selection background, invert the selection
838     // background.
839     if (textColor == c)
840         c = Color(0xff - c.red(), 0xff - c.green(), 0xff - c.blue());
841
842     GraphicsContextStateSaver stateSaver(*context);
843     updateGraphicsContext(context, c, c, 0); // Don't draw text at all!
844
845     // If the text is truncated, let the thing being painted in the truncation
846     // draw its own highlight.
847     int length = m_truncation != cNoTruncation ? m_truncation : m_len;
848     StringView string = textRenderer()->text().createView();
849
850     if (string.length() != static_cast<unsigned>(length) || m_start)
851         string.narrow(m_start, length);
852
853     StringBuilder charactersWithHyphen;
854     bool respectHyphen = ePos == length && hasHyphen();
855     TextRun textRun = constructTextRun(style, font, string, textRenderer()->textLength() - m_start, respectHyphen ? &charactersWithHyphen : 0);
856     if (respectHyphen)
857         ePos = textRun.length();
858
859     LayoutUnit selectionBottom = root()->selectionBottom();
860     LayoutUnit selectionTop = root()->selectionTopAdjustedForPrecedingBlock();
861
862     int deltaY = roundToInt(renderer()->style()->isFlippedLinesWritingMode() ? selectionBottom - logicalBottom() : logicalTop() - selectionTop);
863     int selHeight = max(0, roundToInt(selectionBottom - selectionTop));
864
865     FloatPoint localOrigin(boxOrigin.x(), boxOrigin.y() - deltaY);
866     FloatRect clipRect(localOrigin, FloatSize(m_logicalWidth, selHeight));
867     alignSelectionRectToDevicePixels(clipRect);
868
869     context->clip(clipRect);
870
871     context->drawHighlightForText(font, textRun, localOrigin, selHeight, c, sPos, ePos);
872 }
873
874 void InlineTextBox::paintCompositionBackground(GraphicsContext* context, const FloatPoint& boxOrigin, RenderStyle* style, const Font& font, int startPos, int endPos)
875 {
876     int offset = m_start;
877     int sPos = max(startPos - offset, 0);
878     int ePos = min(endPos - offset, (int)m_len);
879
880     if (sPos >= ePos)
881         return;
882
883     GraphicsContextStateSaver stateSaver(*context);
884
885     Color c = Color(225, 221, 85);
886
887     updateGraphicsContext(context, c, c, 0); // Don't draw text at all!
888
889     int deltaY = renderer()->style()->isFlippedLinesWritingMode() ? selectionBottom() - logicalBottom() : logicalTop() - selectionTop();
890     int selHeight = selectionHeight();
891     FloatPoint localOrigin(boxOrigin.x(), boxOrigin.y() - deltaY);
892     context->drawHighlightForText(font, constructTextRun(style, font), localOrigin, selHeight, c, sPos, ePos);
893 }
894
895 static StrokeStyle textDecorationStyleToStrokeStyle(TextDecorationStyle decorationStyle)
896 {
897     StrokeStyle strokeStyle = SolidStroke;
898     switch (decorationStyle) {
899     case TextDecorationStyleSolid:
900         strokeStyle = SolidStroke;
901         break;
902     case TextDecorationStyleDouble:
903         strokeStyle = DoubleStroke;
904         break;
905     case TextDecorationStyleDotted:
906         strokeStyle = DottedStroke;
907         break;
908     case TextDecorationStyleDashed:
909         strokeStyle = DashedStroke;
910         break;
911     case TextDecorationStyleWavy:
912         strokeStyle = WavyStroke;
913         break;
914     }
915
916     return strokeStyle;
917 }
918
919 static int computeUnderlineOffset(const TextUnderlinePosition underlinePosition, const FontMetrics& fontMetrics, const InlineTextBox* inlineTextBox, const float textDecorationThickness)
920 {
921     // Compute the gap between the font and the underline. Use at least one
922     // pixel gap, if underline is thick then use a bigger gap.
923     const int gap = std::max<int>(1, ceilf(textDecorationThickness / 2.f));
924
925     // According to the specification TextUnderlinePositionAuto should default to 'alphabetic' for horizontal text
926     // and to 'under Left' for vertical text (e.g. japanese). We support only horizontal text for now.
927     switch (underlinePosition) {
928     case TextUnderlinePositionAlphabetic:
929     case TextUnderlinePositionAuto:
930         return fontMetrics.ascent() + gap; // Position underline near the alphabetic baseline.
931     case TextUnderlinePositionUnder: {
932         // Position underline relative to the under edge of the lowest element's content box.
933         const float offset = inlineTextBox->root()->maxLogicalTop() - inlineTextBox->logicalTop();
934         if (offset > 0)
935             return inlineTextBox->logicalHeight() + gap + offset;
936         return inlineTextBox->logicalHeight() + gap;
937     }
938     }
939
940     ASSERT_NOT_REACHED();
941     return fontMetrics.ascent() + gap;
942 }
943
944 static void adjustStepToDecorationLength(float& step, float& controlPointDistance, float length)
945 {
946     ASSERT(step > 0);
947
948     if (length <= 0)
949         return;
950
951     unsigned stepCount = static_cast<unsigned>(length / step);
952
953     // Each Bezier curve starts at the same pixel that the previous one
954     // ended. We need to subtract (stepCount - 1) pixels when calculating the
955     // length covered to account for that.
956     float uncoveredLength = length - (stepCount * step - (stepCount - 1));
957     float adjustment = uncoveredLength / stepCount;
958     step += adjustment;
959     controlPointDistance += adjustment;
960 }
961
962 /*
963  * Draw one cubic Bezier curve and repeat the same pattern long the the decoration's axis.
964  * The start point (p1), controlPoint1, controlPoint2 and end point (p2) of the Bezier curve
965  * form a diamond shape:
966  *
967  *                              step
968  *                         |-----------|
969  *
970  *                   controlPoint1
971  *                         +
972  *
973  *
974  *                  . .
975  *                .     .
976  *              .         .
977  * (x1, y1) p1 +           .            + p2 (x2, y2) - <--- Decoration's axis
978  *                          .         .               |
979  *                            .     .                 |
980  *                              . .                   | controlPointDistance
981  *                                                    |
982  *                                                    |
983  *                         +                          -
984  *                   controlPoint2
985  *
986  *             |-----------|
987  *                 step
988  */
989 static void strokeWavyTextDecoration(GraphicsContext* context, FloatPoint& p1, FloatPoint& p2, float strokeThickness)
990 {
991     context->adjustLineToPixelBoundaries(p1, p2, strokeThickness, context->strokeStyle());
992
993     Path path;
994     path.moveTo(p1);
995
996     // Distance between decoration's axis and Bezier curve's control points.
997     // The height of the curve is based on this distance. Use a minimum of 6 pixels distance since
998     // the actual curve passes approximately at half of that distance, that is 3 pixels.
999     // The minimum height of the curve is also approximately 3 pixels. Increases the curve's height
1000     // as strockThickness increases to make the curve looks better.
1001     float controlPointDistance = 3 * max<float>(2, strokeThickness);
1002
1003     // Increment used to form the diamond shape between start point (p1), control
1004     // points and end point (p2) along the axis of the decoration. Makes the
1005     // curve wider as strockThickness increases to make the curve looks better.
1006     float step = 2 * max<float>(2, strokeThickness);
1007
1008     bool isVerticalLine = (p1.x() == p2.x());
1009
1010     if (isVerticalLine) {
1011         ASSERT(p1.x() == p2.x());
1012
1013         float xAxis = p1.x();
1014         float y1;
1015         float y2;
1016
1017         if (p1.y() < p2.y()) {
1018             y1 = p1.y();
1019             y2 = p2.y();
1020         } else {
1021             y1 = p2.y();
1022             y2 = p1.y();
1023         }
1024
1025         adjustStepToDecorationLength(step, controlPointDistance, y2 - y1);
1026         FloatPoint controlPoint1(xAxis + controlPointDistance, 0);
1027         FloatPoint controlPoint2(xAxis - controlPointDistance, 0);
1028
1029         for (float y = y1; y + 2 * step <= y2;) {
1030             controlPoint1.setY(y + step);
1031             controlPoint2.setY(y + step);
1032             y += 2 * step;
1033             path.addBezierCurveTo(controlPoint1, controlPoint2, FloatPoint(xAxis, y));
1034         }
1035     } else {
1036         ASSERT(p1.y() == p2.y());
1037
1038         float yAxis = p1.y();
1039         float x1;
1040         float x2;
1041
1042         if (p1.x() < p2.x()) {
1043             x1 = p1.x();
1044             x2 = p2.x();
1045         } else {
1046             x1 = p2.x();
1047             x2 = p1.x();
1048         }
1049
1050         adjustStepToDecorationLength(step, controlPointDistance, x2 - x1);
1051         FloatPoint controlPoint1(0, yAxis + controlPointDistance);
1052         FloatPoint controlPoint2(0, yAxis - controlPointDistance);
1053
1054         for (float x = x1; x + 2 * step <= x2;) {
1055             controlPoint1.setX(x + step);
1056             controlPoint2.setX(x + step);
1057             x += 2 * step;
1058             path.addBezierCurveTo(controlPoint1, controlPoint2, FloatPoint(x, yAxis));
1059         }
1060     }
1061
1062     context->setShouldAntialias(true);
1063     context->strokePath(path);
1064 }
1065
1066 void InlineTextBox::paintDecoration(GraphicsContext* context, const FloatPoint& boxOrigin, TextDecoration deco, TextDecorationStyle decorationStyle, const ShadowList* shadowList)
1067 {
1068     GraphicsContextStateSaver stateSaver(*context);
1069
1070     if (m_truncation == cFullTruncation)
1071         return;
1072
1073     FloatPoint localOrigin = boxOrigin;
1074
1075     float width = m_logicalWidth;
1076     if (m_truncation != cNoTruncation) {
1077         width = toRenderText(renderer())->width(m_start, m_truncation, textPos(), isFirstLineStyle());
1078         if (!isLeftToRightDirection())
1079             localOrigin.move(m_logicalWidth - width, 0);
1080     }
1081
1082     // Get the text decoration colors.
1083     Color underline, overline, linethrough;
1084     renderer()->getTextDecorationColors(deco, underline, overline, linethrough, true);
1085     if (isFirstLineStyle())
1086         renderer()->getTextDecorationColors(deco, underline, overline, linethrough, true, true);
1087
1088     // Use a special function for underlines to get the positioning exactly right.
1089     bool isPrinting = textRenderer()->document().printing();
1090
1091     bool linesAreOpaque = !isPrinting && (!(deco & TextDecorationUnderline) || underline.alpha() == 255) && (!(deco & TextDecorationOverline) || overline.alpha() == 255) && (!(deco & TextDecorationLineThrough) || linethrough.alpha() == 255);
1092
1093     RenderStyle* styleToUse = renderer()->style(isFirstLineStyle());
1094     int baseline = styleToUse->fontMetrics().ascent();
1095
1096     size_t shadowCount = shadowList ? shadowList->shadows().size() : 0;
1097     // Set the thick of the line to be 10% (or something else ?)of the computed font size and not less than 1px.
1098     // Using computedFontSize should take care of zoom as well.
1099     const float textDecorationThickness = std::max(1.f, styleToUse->computedFontSize() / 10.f);
1100     context->setStrokeThickness(textDecorationThickness);
1101
1102     int extraOffset = 0;
1103     if (!linesAreOpaque && shadowCount > 1) {
1104         FloatRect clipRect(localOrigin, FloatSize(width, baseline + 2));
1105         for (size_t i = shadowCount; i--; ) {
1106             const ShadowData& s = shadowList->shadows()[i];
1107             FloatRect shadowRect(localOrigin, FloatSize(width, baseline + 2));
1108             shadowRect.inflate(s.blur());
1109             int shadowX = isHorizontal() ? s.x() : s.y();
1110             int shadowY = isHorizontal() ? s.y() : -s.x();
1111             shadowRect.move(shadowX, shadowY);
1112             clipRect.unite(shadowRect);
1113             extraOffset = max(extraOffset, max(0, shadowY) + s.blur());
1114         }
1115         context->clip(clipRect);
1116         extraOffset += baseline + 2;
1117         localOrigin.move(0, extraOffset);
1118     }
1119
1120     for (size_t i = max(static_cast<size_t>(1), shadowCount); i--; ) {
1121         // Even if we have no shadows, we still want to run the code below this once.
1122         if (i < shadowCount) {
1123             if (!i) {
1124                 // The last set of lines paints normally inside the clip.
1125                 localOrigin.move(0, -extraOffset);
1126                 extraOffset = 0;
1127             }
1128             const ShadowData& shadow = shadowList->shadows()[i];
1129             int shadowX = isHorizontal() ? shadow.x() : shadow.y();
1130             int shadowY = isHorizontal() ? shadow.y() : -shadow.x();
1131             context->setShadow(FloatSize(shadowX, shadowY - extraOffset), shadow.blur(), shadow.color());
1132         }
1133
1134         // Offset between lines - always non-zero, so lines never cross each other.
1135         float doubleOffset = textDecorationThickness + 1.f;
1136         context->setStrokeStyle(textDecorationStyleToStrokeStyle(decorationStyle));
1137         if (deco & TextDecorationUnderline) {
1138             context->setStrokeColor(underline);
1139             const int underlineOffset = computeUnderlineOffset(styleToUse->textUnderlinePosition(), styleToUse->fontMetrics(), this, textDecorationThickness);
1140             switch (decorationStyle) {
1141             case TextDecorationStyleWavy: {
1142                 FloatPoint start(localOrigin.x(), localOrigin.y() + underlineOffset + doubleOffset);
1143                 FloatPoint end(localOrigin.x() + width, localOrigin.y() + underlineOffset + doubleOffset);
1144                 strokeWavyTextDecoration(context, start, end, textDecorationThickness);
1145                 break;
1146             }
1147             default:
1148                 context->drawLineForText(FloatPoint(localOrigin.x(), localOrigin.y() + underlineOffset), width, isPrinting);
1149
1150                 if (decorationStyle == TextDecorationStyleDouble)
1151                     context->drawLineForText(FloatPoint(localOrigin.x(), localOrigin.y() + underlineOffset + doubleOffset), width, isPrinting);
1152             }
1153         }
1154         if (deco & TextDecorationOverline) {
1155             context->setStrokeColor(overline);
1156             switch (decorationStyle) {
1157             case TextDecorationStyleWavy: {
1158                 FloatPoint start(localOrigin.x(), localOrigin.y() - doubleOffset);
1159                 FloatPoint end(localOrigin.x() + width, localOrigin.y() - doubleOffset);
1160                 strokeWavyTextDecoration(context, start, end, textDecorationThickness);
1161                 break;
1162             }
1163             default:
1164                 context->drawLineForText(localOrigin, width, isPrinting);
1165                 if (decorationStyle == TextDecorationStyleDouble)
1166                     context->drawLineForText(FloatPoint(localOrigin.x(), localOrigin.y() - doubleOffset), width, isPrinting);
1167             }
1168         }
1169         if (deco & TextDecorationLineThrough) {
1170             context->setStrokeColor(linethrough);
1171             switch (decorationStyle) {
1172             case TextDecorationStyleWavy: {
1173                 FloatPoint start(localOrigin.x(), localOrigin.y() + 2 * baseline / 3);
1174                 FloatPoint end(localOrigin.x() + width, localOrigin.y() + 2 * baseline / 3);
1175                 strokeWavyTextDecoration(context, start, end, textDecorationThickness);
1176                 break;
1177             }
1178             default:
1179                 context->drawLineForText(FloatPoint(localOrigin.x(), localOrigin.y() + 2 * baseline / 3), width, isPrinting);
1180                 if (decorationStyle == TextDecorationStyleDouble)
1181                     context->drawLineForText(FloatPoint(localOrigin.x(), localOrigin.y() + doubleOffset + 2 * baseline / 3), width, isPrinting);
1182             }
1183         }
1184     }
1185 }
1186
1187 static GraphicsContext::DocumentMarkerLineStyle lineStyleForMarkerType(DocumentMarker::MarkerType markerType)
1188 {
1189     switch (markerType) {
1190     case DocumentMarker::Spelling:
1191         return GraphicsContext::DocumentMarkerSpellingLineStyle;
1192     case DocumentMarker::Grammar:
1193         return GraphicsContext::DocumentMarkerGrammarLineStyle;
1194     default:
1195         ASSERT_NOT_REACHED();
1196         return GraphicsContext::DocumentMarkerSpellingLineStyle;
1197     }
1198 }
1199
1200 void InlineTextBox::paintDocumentMarker(GraphicsContext* pt, const FloatPoint& boxOrigin, DocumentMarker* marker, RenderStyle* style, const Font& font, bool grammar)
1201 {
1202     // Never print spelling/grammar markers (5327887)
1203     if (textRenderer()->document().printing())
1204         return;
1205
1206     if (m_truncation == cFullTruncation)
1207         return;
1208
1209     float start = 0; // start of line to draw, relative to tx
1210     float width = m_logicalWidth; // how much line to draw
1211
1212     // Determine whether we need to measure text
1213     bool markerSpansWholeBox = true;
1214     if (m_start <= (int)marker->startOffset())
1215         markerSpansWholeBox = false;
1216     if ((end() + 1) != marker->endOffset()) // end points at the last char, not past it
1217         markerSpansWholeBox = false;
1218     if (m_truncation != cNoTruncation)
1219         markerSpansWholeBox = false;
1220
1221     if (!markerSpansWholeBox || grammar) {
1222         int startPosition = max<int>(marker->startOffset() - m_start, 0);
1223         int endPosition = min<int>(marker->endOffset() - m_start, m_len);
1224
1225         if (m_truncation != cNoTruncation)
1226             endPosition = min<int>(endPosition, m_truncation);
1227
1228         // Calculate start & width
1229         int deltaY = renderer()->style()->isFlippedLinesWritingMode() ? selectionBottom() - logicalBottom() : logicalTop() - selectionTop();
1230         int selHeight = selectionHeight();
1231         FloatPoint startPoint(boxOrigin.x(), boxOrigin.y() - deltaY);
1232         TextRun run = constructTextRun(style, font);
1233
1234         // FIXME: Convert the document markers to float rects.
1235         IntRect markerRect = enclosingIntRect(font.selectionRectForText(run, startPoint, selHeight, startPosition, endPosition));
1236         start = markerRect.x() - startPoint.x();
1237         width = markerRect.width();
1238
1239         // Store rendered rects for bad grammar markers, so we can hit-test against it elsewhere in order to
1240         // display a toolTip. We don't do this for misspelling markers.
1241         if (grammar) {
1242             markerRect.move(-boxOrigin.x(), -boxOrigin.y());
1243             markerRect = renderer()->localToAbsoluteQuad(FloatRect(markerRect)).enclosingBoundingBox();
1244             toRenderedDocumentMarker(marker)->setRenderedRect(markerRect);
1245         }
1246     }
1247
1248     // IMPORTANT: The misspelling underline is not considered when calculating the text bounds, so we have to
1249     // make sure to fit within those bounds.  This means the top pixel(s) of the underline will overlap the
1250     // bottom pixel(s) of the glyphs in smaller font sizes.  The alternatives are to increase the line spacing (bad!!)
1251     // or decrease the underline thickness.  The overlap is actually the most useful, and matches what AppKit does.
1252     // So, we generally place the underline at the bottom of the text, but in larger fonts that's not so good so
1253     // we pin to two pixels under the baseline.
1254     int lineThickness = misspellingLineThickness;
1255     int baseline = renderer()->style(isFirstLineStyle())->fontMetrics().ascent();
1256     int descent = logicalHeight() - baseline;
1257     int underlineOffset;
1258     if (descent <= (2 + lineThickness)) {
1259         // Place the underline at the very bottom of the text in small/medium fonts.
1260         underlineOffset = logicalHeight() - lineThickness;
1261     } else {
1262         // In larger fonts, though, place the underline up near the baseline to prevent a big gap.
1263         underlineOffset = baseline + 2;
1264     }
1265     pt->drawLineForDocumentMarker(FloatPoint(boxOrigin.x() + start, boxOrigin.y() + underlineOffset), width, lineStyleForMarkerType(marker->type()));
1266 }
1267
1268 void InlineTextBox::paintTextMatchMarker(GraphicsContext* pt, const FloatPoint& boxOrigin, DocumentMarker* marker, RenderStyle* style, const Font& font)
1269 {
1270     // Use same y positioning and height as for selection, so that when the selection and this highlight are on
1271     // the same word there are no pieces sticking out.
1272     int deltaY = renderer()->style()->isFlippedLinesWritingMode() ? selectionBottom() - logicalBottom() : logicalTop() - selectionTop();
1273     int selHeight = selectionHeight();
1274
1275     int sPos = max(marker->startOffset() - m_start, (unsigned)0);
1276     int ePos = min(marker->endOffset() - m_start, (unsigned)m_len);
1277     TextRun run = constructTextRun(style, font);
1278
1279     // Always compute and store the rect associated with this marker. The computed rect is in absolute coordinates.
1280     IntRect markerRect = enclosingIntRect(font.selectionRectForText(run, IntPoint(x(), selectionTop()), selHeight, sPos, ePos));
1281     markerRect = renderer()->localToAbsoluteQuad(FloatRect(markerRect)).enclosingBoundingBox();
1282     toRenderedDocumentMarker(marker)->setRenderedRect(markerRect);
1283
1284     // Optionally highlight the text
1285     if (renderer()->frame()->editor().markedTextMatchesAreHighlighted()) {
1286         Color color = marker->activeMatch() ?
1287             RenderTheme::theme().platformActiveTextSearchHighlightColor() :
1288             RenderTheme::theme().platformInactiveTextSearchHighlightColor();
1289         GraphicsContextStateSaver stateSaver(*pt);
1290         updateGraphicsContext(pt, color, color, 0); // Don't draw text at all!
1291         pt->clip(FloatRect(boxOrigin.x(), boxOrigin.y() - deltaY, m_logicalWidth, selHeight));
1292         pt->drawHighlightForText(font, run, FloatPoint(boxOrigin.x(), boxOrigin.y() - deltaY), selHeight, color, sPos, ePos);
1293     }
1294 }
1295
1296 void InlineTextBox::paintDocumentMarkers(GraphicsContext* pt, const FloatPoint& boxOrigin, RenderStyle* style, const Font& font, bool background)
1297 {
1298     if (!renderer()->node())
1299         return;
1300
1301     Vector<DocumentMarker*> markers = renderer()->document().markers()->markersFor(renderer()->node());
1302     Vector<DocumentMarker*>::const_iterator markerIt = markers.begin();
1303
1304     // Give any document markers that touch this run a chance to draw before the text has been drawn.
1305     // Note end() points at the last char, not one past it like endOffset and ranges do.
1306     for ( ; markerIt != markers.end(); markerIt++) {
1307         DocumentMarker* marker = *markerIt;
1308
1309         // Paint either the background markers or the foreground markers, but not both
1310         switch (marker->type()) {
1311             case DocumentMarker::Grammar:
1312             case DocumentMarker::Spelling:
1313                 if (background)
1314                     continue;
1315                 break;
1316             case DocumentMarker::TextMatch:
1317                 if (!background)
1318                     continue;
1319                 break;
1320             default:
1321                 continue;
1322         }
1323
1324         if (marker->endOffset() <= start())
1325             // marker is completely before this run.  This might be a marker that sits before the
1326             // first run we draw, or markers that were within runs we skipped due to truncation.
1327             continue;
1328
1329         if (marker->startOffset() > end())
1330             // marker is completely after this run, bail.  A later run will paint it.
1331             break;
1332
1333         // marker intersects this run.  Paint it.
1334         switch (marker->type()) {
1335             case DocumentMarker::Spelling:
1336                 paintDocumentMarker(pt, boxOrigin, marker, style, font, false);
1337                 break;
1338             case DocumentMarker::Grammar:
1339                 paintDocumentMarker(pt, boxOrigin, marker, style, font, true);
1340                 break;
1341             case DocumentMarker::TextMatch:
1342                 paintTextMatchMarker(pt, boxOrigin, marker, style, font);
1343                 break;
1344             default:
1345                 ASSERT_NOT_REACHED();
1346         }
1347
1348     }
1349 }
1350
1351 void InlineTextBox::paintCompositionUnderline(GraphicsContext* ctx, const FloatPoint& boxOrigin, const CompositionUnderline& underline)
1352 {
1353     if (m_truncation == cFullTruncation)
1354         return;
1355
1356     float start = 0; // start of line to draw, relative to tx
1357     float width = m_logicalWidth; // how much line to draw
1358     bool useWholeWidth = true;
1359     unsigned paintStart = m_start;
1360     unsigned paintEnd = end() + 1; // end points at the last char, not past it
1361     if (paintStart <= underline.startOffset) {
1362         paintStart = underline.startOffset;
1363         useWholeWidth = false;
1364         start = toRenderText(renderer())->width(m_start, paintStart - m_start, textPos(), isFirstLineStyle());
1365     }
1366     if (paintEnd != underline.endOffset) {      // end points at the last char, not past it
1367         paintEnd = min(paintEnd, (unsigned)underline.endOffset);
1368         useWholeWidth = false;
1369     }
1370     if (m_truncation != cNoTruncation) {
1371         paintEnd = min(paintEnd, (unsigned)m_start + m_truncation);
1372         useWholeWidth = false;
1373     }
1374     if (!useWholeWidth) {
1375         width = toRenderText(renderer())->width(paintStart, paintEnd - paintStart, textPos() + start, isFirstLineStyle());
1376     }
1377
1378     // Thick marked text underlines are 2px thick as long as there is room for the 2px line under the baseline.
1379     // All other marked text underlines are 1px thick.
1380     // If there's not enough space the underline will touch or overlap characters.
1381     int lineThickness = 1;
1382     int baseline = renderer()->style(isFirstLineStyle())->fontMetrics().ascent();
1383     if (underline.thick && logicalHeight() - baseline >= 2)
1384         lineThickness = 2;
1385
1386     // We need to have some space between underlines of subsequent clauses, because some input methods do not use different underline styles for those.
1387     // We make each line shorter, which has a harmless side effect of shortening the first and last clauses, too.
1388     start += 1;
1389     width -= 2;
1390
1391     ctx->setStrokeColor(underline.color);
1392     ctx->setStrokeThickness(lineThickness);
1393     ctx->drawLineForText(FloatPoint(boxOrigin.x() + start, boxOrigin.y() + logicalHeight() - lineThickness), width, textRenderer()->document().printing());
1394 }
1395
1396 int InlineTextBox::caretMinOffset() const
1397 {
1398     return m_start;
1399 }
1400
1401 int InlineTextBox::caretMaxOffset() const
1402 {
1403     return m_start + m_len;
1404 }
1405
1406 float InlineTextBox::textPos() const
1407 {
1408     // When computing the width of a text run, RenderBlock::computeInlineDirectionPositionsForLine() doesn't include the actual offset
1409     // from the containing block edge in its measurement. textPos() should be consistent so the text are rendered in the same width.
1410     if (logicalLeft() == 0)
1411         return 0;
1412     return logicalLeft() - root()->logicalLeft();
1413 }
1414
1415 int InlineTextBox::offsetForPosition(float lineOffset, bool includePartialGlyphs) const
1416 {
1417     if (isLineBreak())
1418         return 0;
1419
1420     if (lineOffset - logicalLeft() > logicalWidth())
1421         return isLeftToRightDirection() ? len() : 0;
1422     if (lineOffset - logicalLeft() < 0)
1423         return isLeftToRightDirection() ? 0 : len();
1424
1425     FontCachePurgePreventer fontCachePurgePreventer;
1426
1427     RenderText* text = toRenderText(renderer());
1428     RenderStyle* style = text->style(isFirstLineStyle());
1429     const Font& font = style->font();
1430     return font.offsetForPosition(constructTextRun(style, font), lineOffset - logicalLeft(), includePartialGlyphs);
1431 }
1432
1433 float InlineTextBox::positionForOffset(int offset) const
1434 {
1435     ASSERT(offset >= m_start);
1436     ASSERT(offset <= m_start + m_len);
1437
1438     if (isLineBreak())
1439         return logicalLeft();
1440
1441     FontCachePurgePreventer fontCachePurgePreventer;
1442
1443     RenderText* text = toRenderText(renderer());
1444     RenderStyle* styleToUse = text->style(isFirstLineStyle());
1445     ASSERT(styleToUse);
1446     const Font& font = styleToUse->font();
1447     int from = !isLeftToRightDirection() ? offset - m_start : 0;
1448     int to = !isLeftToRightDirection() ? m_len : offset - m_start;
1449     // FIXME: Do we need to add rightBearing here?
1450     return font.selectionRectForText(constructTextRun(styleToUse, font), IntPoint(logicalLeft(), 0), 0, from, to).maxX();
1451 }
1452
1453 bool InlineTextBox::containsCaretOffset(int offset) const
1454 {
1455     // Offsets before the box are never "in".
1456     if (offset < m_start)
1457         return false;
1458
1459     int pastEnd = m_start + m_len;
1460
1461     // Offsets inside the box (not at either edge) are always "in".
1462     if (offset < pastEnd)
1463         return true;
1464
1465     // Offsets outside the box are always "out".
1466     if (offset > pastEnd)
1467         return false;
1468
1469     // Offsets at the end are "out" for line breaks (they are on the next line).
1470     if (isLineBreak())
1471         return false;
1472
1473     // Offsets at the end are "in" for normal boxes (but the caller has to check affinity).
1474     return true;
1475 }
1476
1477 void InlineTextBox::characterWidths(Vector<float>& widths) const
1478 {
1479     FontCachePurgePreventer fontCachePurgePreventer;
1480
1481     RenderText* textObj = textRenderer();
1482     RenderStyle* styleToUse = textObj->style(isFirstLineStyle());
1483     const Font& font = styleToUse->font();
1484
1485     TextRun textRun = constructTextRun(styleToUse, font);
1486
1487     GlyphBuffer glyphBuffer;
1488     WidthIterator it(&font, textRun);
1489     float lastWidth = 0;
1490     widths.resize(m_len);
1491     for (unsigned i = 0; i < m_len; i++) {
1492         it.advance(i + 1, &glyphBuffer);
1493         widths[i] = it.m_runWidthSoFar - lastWidth;
1494         lastWidth = it.m_runWidthSoFar;
1495     }
1496 }
1497
1498 TextRun InlineTextBox::constructTextRun(RenderStyle* style, const Font& font, StringBuilder* charactersWithHyphen) const
1499 {
1500     ASSERT(style);
1501
1502     RenderText* textRenderer = this->textRenderer();
1503     ASSERT(textRenderer);
1504     ASSERT(textRenderer->text());
1505
1506     StringView string = textRenderer->text().createView();
1507     unsigned startPos = start();
1508     unsigned length = len();
1509
1510     if (string.length() != length || startPos)
1511         string.narrow(startPos, length);
1512
1513     return constructTextRun(style, font, string, textRenderer->textLength() - startPos, charactersWithHyphen);
1514 }
1515
1516 TextRun InlineTextBox::constructTextRun(RenderStyle* style, const Font& font, StringView string, int maximumLength, StringBuilder* charactersWithHyphen) const
1517 {
1518     ASSERT(style);
1519
1520     RenderText* textRenderer = this->textRenderer();
1521     ASSERT(textRenderer);
1522
1523     if (charactersWithHyphen) {
1524         const AtomicString& hyphenString = style->hyphenString();
1525         charactersWithHyphen->reserveCapacity(string.length() + hyphenString.length());
1526         charactersWithHyphen->append(string);
1527         charactersWithHyphen->append(hyphenString);
1528         string = charactersWithHyphen->toString().createView();
1529         maximumLength = string.length();
1530     }
1531
1532     ASSERT(maximumLength >= static_cast<int>(string.length()));
1533
1534     TextRun run(string, textPos(), expansion(), expansionBehavior(), direction(), dirOverride() || style->rtlOrdering() == VisualOrder, !textRenderer->canUseSimpleFontCodePath());
1535     run.setTabSize(!style->collapseWhiteSpace(), style->tabSize());
1536     if (textRunNeedsRenderingContext(font))
1537         run.setRenderingContext(SVGTextRunRenderingContext::create(textRenderer));
1538
1539     // Propagate the maximum length of the characters buffer to the TextRun, even when we're only processing a substring.
1540     run.setCharactersLength(maximumLength);
1541     ASSERT(run.charactersLength() >= run.length());
1542     return run;
1543 }
1544
1545 TextRun InlineTextBox::constructTextRunForInspector(RenderStyle* style, const Font& font) const
1546 {
1547     return InlineTextBox::constructTextRun(style, font);
1548 }
1549
1550 #ifndef NDEBUG
1551
1552 const char* InlineTextBox::boxName() const
1553 {
1554     return "InlineTextBox";
1555 }
1556
1557 void InlineTextBox::showBox(int printedCharacters) const
1558 {
1559     const RenderText* obj = toRenderText(renderer());
1560     String value = obj->text();
1561     value = value.substring(start(), len());
1562     value.replaceWithLiteral('\\', "\\\\");
1563     value.replaceWithLiteral('\n', "\\n");
1564     printedCharacters += fprintf(stderr, "%s\t%p", boxName(), this);
1565     for (; printedCharacters < showTreeCharacterOffset; printedCharacters++)
1566         fputc(' ', stderr);
1567     printedCharacters = fprintf(stderr, "\t%s %p", obj->renderName(), obj);
1568     const int rendererCharacterOffset = 24;
1569     for (; printedCharacters < rendererCharacterOffset; printedCharacters++)
1570         fputc(' ', stderr);
1571     fprintf(stderr, "(%d,%d) \"%s\"\n", start(), start() + len(), value.utf8().data());
1572 }
1573
1574 #endif
1575
1576 } // namespace WebCore