Addressing post-review comment on r174297.
[WebKit-https.git] / Source / WebCore / rendering / RenderText.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, 2013 Apple Inc. All rights reserved.
5  * Copyright (C) 2006 Andrew Wellington (proton@wiretapped.net)
6  * Copyright (C) 2006 Graham Dennis (graham.dennis@gmail.com)
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Library General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Library General Public License for more details.
17  *
18  * You should have received a copy of the GNU Library General Public License
19  * along with this library; see the file COPYING.LIB.  If not, write to
20  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21  * Boston, MA 02110-1301, USA.
22  *
23  */
24
25 #include "config.h"
26 #include "RenderText.h"
27
28 #include "AXObjectCache.h"
29 #include "EllipsisBox.h"
30 #include "FloatQuad.h"
31 #include "Frame.h"
32 #include "FrameView.h"
33 #include "Hyphenation.h"
34 #include "InlineTextBox.h"
35 #include "Range.h"
36 #include "RenderBlock.h"
37 #include "RenderCombineText.h"
38 #include "RenderLayer.h"
39 #include "RenderView.h"
40 #include "Settings.h"
41 #include "SimpleLineLayoutFunctions.h"
42 #include "Text.h"
43 #include "TextBreakIterator.h"
44 #include "TextResourceDecoder.h"
45 #include "VisiblePosition.h"
46 #include "break_lines.h"
47 #include <wtf/NeverDestroyed.h>
48 #include <wtf/text/StringBuffer.h>
49 #include <wtf/text/StringBuilder.h>
50 #include <wtf/unicode/CharacterNames.h>
51
52 #if PLATFORM(IOS)
53 #include "Document.h"
54 #include "EditorClient.h"
55 #include "LogicalSelectionOffsetCaches.h"
56 #include "Page.h"
57 #include "SelectionRect.h"
58 #endif
59
60 using namespace WTF;
61 using namespace Unicode;
62
63 namespace WebCore {
64
65 struct SameSizeAsRenderText : public RenderObject {
66     uint32_t bitfields : 16;
67 #if ENABLE(IOS_TEXT_AUTOSIZING)
68     float candidateTextSize;
69 #endif
70     float widths[4];
71     String text;
72     void* pointers[2];
73 };
74
75 COMPILE_ASSERT(sizeof(RenderText) == sizeof(SameSizeAsRenderText), RenderText_should_stay_small);
76
77 class SecureTextTimer;
78 typedef HashMap<RenderText*, SecureTextTimer*> SecureTextTimerMap;
79 static SecureTextTimerMap* gSecureTextTimers = 0;
80
81 class SecureTextTimer : public TimerBase {
82 public:
83     SecureTextTimer(RenderText* renderText)
84         : m_renderText(renderText)
85         , m_lastTypedCharacterOffset(-1)
86     {
87     }
88
89     void restartWithNewText(unsigned lastTypedCharacterOffset)
90     {
91         m_lastTypedCharacterOffset = lastTypedCharacterOffset;
92         const Settings& settings = m_renderText->frame().settings();
93         startOneShot(settings.passwordEchoDurationInSeconds());
94     }
95     void invalidate() { m_lastTypedCharacterOffset = -1; }
96     unsigned lastTypedCharacterOffset() { return m_lastTypedCharacterOffset; }
97
98 private:
99     virtual void fired()
100     {
101         ASSERT(gSecureTextTimers->contains(m_renderText));
102         m_renderText->setText(m_renderText->text(), true /* forcing setting text as it may be masked later */);
103     }
104
105     RenderText* m_renderText;
106     int m_lastTypedCharacterOffset;
107 };
108
109 static HashMap<const RenderText*, String>& originalTextMap()
110 {
111     static NeverDestroyed<HashMap<const RenderText*, String>> map;
112     return map;
113 }
114
115 void makeCapitalized(String* string, UChar previous)
116 {
117     // FIXME: Need to change this to use u_strToTitle instead of u_totitle and to consider locale.
118
119     if (string->isNull())
120         return;
121
122     unsigned length = string->length();
123     const StringImpl& stringImpl = *string->impl();
124
125     if (length >= std::numeric_limits<unsigned>::max())
126         CRASH();
127
128     StringBuffer<UChar> stringWithPrevious(length + 1);
129     stringWithPrevious[0] = previous == noBreakSpace ? ' ' : previous;
130     for (unsigned i = 1; i < length + 1; i++) {
131         // Replace &nbsp with a real space since ICU no longer treats &nbsp as a word separator.
132         if (stringImpl[i - 1] == noBreakSpace)
133             stringWithPrevious[i] = ' ';
134         else
135             stringWithPrevious[i] = stringImpl[i - 1];
136     }
137
138     TextBreakIterator* boundary = wordBreakIterator(StringView(stringWithPrevious.characters(), length + 1));
139     if (!boundary)
140         return;
141
142     StringBuilder result;
143     result.reserveCapacity(length);
144
145     int32_t endOfWord;
146     int32_t startOfWord = textBreakFirst(boundary);
147     for (endOfWord = textBreakNext(boundary); endOfWord != TextBreakDone; startOfWord = endOfWord, endOfWord = textBreakNext(boundary)) {
148         if (startOfWord) // Ignore first char of previous string
149             result.append(stringImpl[startOfWord - 1] == noBreakSpace ? noBreakSpace : u_totitle(stringWithPrevious[startOfWord]));
150         for (int i = startOfWord + 1; i < endOfWord; i++)
151             result.append(stringImpl[i - 1]);
152     }
153
154     *string = result.toString();
155 }
156
157 inline RenderText::RenderText(Node& node, const String& text)
158     : RenderObject(node)
159     , m_hasTab(false)
160     , m_linesDirty(false)
161     , m_containsReversedText(false)
162     , m_isAllASCII(text.containsOnlyASCII())
163     , m_knownToHaveNoOverflowAndNoFallbackFonts(false)
164     , m_useBackslashAsYenSymbol(false)
165     , m_originalTextDiffersFromRendered(false)
166 #if ENABLE(IOS_TEXT_AUTOSIZING)
167     , m_candidateComputedTextSize(0)
168 #endif
169     , m_minWidth(-1)
170     , m_maxWidth(-1)
171     , m_beginMinWidth(0)
172     , m_endMinWidth(0)
173     , m_text(text)
174 {
175     ASSERT(!m_text.isNull());
176     setIsText();
177     m_canUseSimpleFontCodePath = computeCanUseSimpleFontCodePath();
178     view().frameView().incrementVisuallyNonEmptyCharacterCount(textLength());
179 }
180
181 RenderText::RenderText(Text& textNode, const String& text)
182     : RenderText(static_cast<Node&>(textNode), text)
183 {
184 }
185
186 RenderText::RenderText(Document& document, const String& text)
187     : RenderText(static_cast<Node&>(document), text)
188 {
189 }
190
191 RenderText::~RenderText()
192 {
193     if (m_originalTextDiffersFromRendered)
194         originalTextMap().remove(this);
195 }
196
197 const char* RenderText::renderName() const
198 {
199     return "RenderText";
200 }
201
202 Text* RenderText::textNode() const
203 {
204     return downcast<Text>(RenderObject::node());
205 }
206
207 bool RenderText::isTextFragment() const
208 {
209     return false;
210 }
211
212 bool RenderText::computeUseBackslashAsYenSymbol() const
213 {
214     const RenderStyle& style = this->style();
215     const FontDescription& fontDescription = style.font().fontDescription();
216     if (style.font().useBackslashAsYenSymbol())
217         return true;
218     if (fontDescription.isSpecifiedFont())
219         return false;
220     const TextEncoding* encoding = document().decoder() ? &document().decoder()->encoding() : 0;
221     if (encoding && encoding->backslashAsCurrencySymbol() != '\\')
222         return true;
223     return false;
224 }
225
226 void RenderText::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
227 {
228     // There is no need to ever schedule repaints from a style change of a text run, since
229     // we already did this for the parent of the text run.
230     // We do have to schedule layouts, though, since a style change can force us to
231     // need to relayout.
232     if (diff == StyleDifferenceLayout) {
233         setNeedsLayoutAndPrefWidthsRecalc();
234         m_knownToHaveNoOverflowAndNoFallbackFonts = false;
235     }
236
237     const RenderStyle& newStyle = style();
238     bool needsResetText = false;
239     if (!oldStyle) {
240         m_useBackslashAsYenSymbol = computeUseBackslashAsYenSymbol();
241         needsResetText = m_useBackslashAsYenSymbol;
242     } else if (oldStyle->font().useBackslashAsYenSymbol() != newStyle.font().useBackslashAsYenSymbol()) {
243         m_useBackslashAsYenSymbol = computeUseBackslashAsYenSymbol();
244         needsResetText = true;
245     }
246
247     ETextTransform oldTransform = oldStyle ? oldStyle->textTransform() : TTNONE;
248     ETextSecurity oldSecurity = oldStyle ? oldStyle->textSecurity() : TSNONE;
249     if (needsResetText || oldTransform != newStyle.textTransform() || oldSecurity != newStyle.textSecurity())
250         RenderText::setText(originalText(), true);
251 }
252
253 void RenderText::removeAndDestroyTextBoxes()
254 {
255     if (!documentBeingDestroyed())
256         m_lineBoxes.removeAllFromParent(*this);
257 #if !ASSERT_WITH_SECURITY_IMPLICATION_DISABLED
258     else
259         m_lineBoxes.invalidateParentChildLists();
260 #endif
261     m_lineBoxes.deleteAll();
262 }
263
264 void RenderText::willBeDestroyed()
265 {
266     if (SecureTextTimer* secureTextTimer = gSecureTextTimers ? gSecureTextTimers->take(this) : 0)
267         delete secureTextTimer;
268
269     removeAndDestroyTextBoxes();
270     RenderObject::willBeDestroyed();
271 }
272
273 void RenderText::deleteLineBoxesBeforeSimpleLineLayout()
274 {
275     m_lineBoxes.deleteAll();
276 }
277
278 String RenderText::originalText() const
279 {
280     return m_originalTextDiffersFromRendered ? originalTextMap().get(this) : m_text;
281 }
282
283 void RenderText::absoluteRects(Vector<IntRect>& rects, const LayoutPoint& accumulatedOffset) const
284 {
285     if (auto layout = simpleLineLayout()) {
286         rects.appendVector(collectTextAbsoluteRects(*this, *layout, accumulatedOffset));
287         return;
288     }
289     rects.appendVector(m_lineBoxes.absoluteRects(accumulatedOffset));
290 }
291
292 Vector<IntRect> RenderText::absoluteRectsForRange(unsigned start, unsigned end, bool useSelectionHeight, bool* wasFixed) const
293 {
294     const_cast<RenderText&>(*this).ensureLineBoxes();
295
296     // Work around signed/unsigned issues. This function takes unsigneds, and is often passed UINT_MAX
297     // to mean "all the way to the end". InlineTextBox coordinates are unsigneds, so changing this 
298     // function to take ints causes various internal mismatches. But selectionRect takes ints, and 
299     // passing UINT_MAX to it causes trouble. Ideally we'd change selectionRect to take unsigneds, but 
300     // that would cause many ripple effects, so for now we'll just clamp our unsigned parameters to INT_MAX.
301     ASSERT(end == UINT_MAX || end <= INT_MAX);
302     ASSERT(start <= INT_MAX);
303     start = std::min(start, static_cast<unsigned>(INT_MAX));
304     end = std::min(end, static_cast<unsigned>(INT_MAX));
305     
306     return m_lineBoxes.absoluteRectsForRange(*this, start, end, useSelectionHeight, wasFixed);
307 }
308
309 #if PLATFORM(IOS)
310 // This function is similar in spirit to addLineBoxRects, but returns rectangles
311 // which are annotated with additional state which helps the iPhone draw selections in its unique way.
312 // Full annotations are added in this class.
313 void RenderText::collectSelectionRects(Vector<SelectionRect>& rects, unsigned start, unsigned end)
314 {
315     // FIXME: Work around signed/unsigned issues. This function takes unsigneds, and is often passed UINT_MAX
316     // to mean "all the way to the end". InlineTextBox coordinates are unsigneds, so changing this 
317     // function to take ints causes various internal mismatches. But selectionRect takes ints, and 
318     // passing UINT_MAX to it causes trouble. Ideally we'd change selectionRect to take unsigneds, but 
319     // that would cause many ripple effects, so for now we'll just clamp our unsigned parameters to INT_MAX.
320     ASSERT(end == std::numeric_limits<unsigned>::max() || end <= std::numeric_limits<int>::max());
321     ASSERT(start <= std::numeric_limits<int>::max());
322     start = std::min(start, static_cast<unsigned>(std::numeric_limits<int>::max()));
323     end = std::min(end, static_cast<unsigned>(std::numeric_limits<int>::max()));
324
325     for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox()) {
326         LayoutRect rect;
327         // Note, box->end() returns the index of the last character, not the index past it.
328         if (start <= box->start() && box->end() < end)
329             rect = box->localSelectionRect(start, end);
330         else {
331             unsigned realEnd = std::min(box->end() + 1, end);
332             rect = box->localSelectionRect(start, realEnd);
333             if (rect.isEmpty())
334                 continue;
335         }
336
337         if (box->root().isFirstAfterPageBreak()) {
338             if (box->isHorizontal())
339                 rect.shiftYEdgeTo(box->root().lineTopWithLeading());
340             else
341                 rect.shiftXEdgeTo(box->root().lineTopWithLeading());
342         }
343
344         RenderBlock* containingBlock = this->containingBlock();
345         // Map rect, extended left to leftOffset, and right to rightOffset, through transforms to get minX and maxX.
346         LogicalSelectionOffsetCaches cache(*containingBlock);
347         LayoutUnit leftOffset = containingBlock->logicalLeftSelectionOffset(*containingBlock, box->logicalTop(), cache);
348         LayoutUnit rightOffset = containingBlock->logicalRightSelectionOffset(*containingBlock, box->logicalTop(), cache);
349         LayoutRect extentsRect = rect;
350         if (box->isHorizontal()) {
351             extentsRect.setX(leftOffset);
352             extentsRect.setWidth(rightOffset - leftOffset);
353         } else {
354             extentsRect.setY(leftOffset);
355             extentsRect.setHeight(rightOffset - leftOffset);
356         }
357         extentsRect = localToAbsoluteQuad(FloatRect(extentsRect)).enclosingBoundingBox();
358         if (!box->isHorizontal())
359             extentsRect = extentsRect.transposedRect();
360         bool isFirstOnLine = !box->previousOnLineExists();
361         bool isLastOnLine = !box->nextOnLineExists();
362         if (containingBlock->isRubyBase() || containingBlock->isRubyText())
363             isLastOnLine = !containingBlock->containingBlock()->inlineBoxWrapper()->nextOnLineExists();
364
365         bool containsStart = box->start() <= start && box->end() + 1 >= start;
366         bool containsEnd = box->start() <= end && box->end() + 1 >= end;
367
368         bool isFixed = false;
369         IntRect absRect = localToAbsoluteQuad(FloatRect(rect), false, &isFixed).enclosingBoundingBox();
370         bool boxIsHorizontal = !box->isSVGInlineTextBox() ? box->isHorizontal() : !style().svgStyle().isVerticalWritingMode();
371         // If the containing block is an inline element, we want to check the inlineBoxWrapper orientation
372         // to determine the orientation of the block. In this case we also use the inlineBoxWrapper to
373         // determine if the element is the last on the line.
374         if (containingBlock->inlineBoxWrapper()) {
375             if (containingBlock->inlineBoxWrapper()->isHorizontal() != boxIsHorizontal) {
376                 boxIsHorizontal = containingBlock->inlineBoxWrapper()->isHorizontal();
377                 isLastOnLine = !containingBlock->inlineBoxWrapper()->nextOnLineExists();
378             }
379         }
380
381         rects.append(SelectionRect(absRect, box->direction(), extentsRect.x(), extentsRect.maxX(), extentsRect.maxY(), 0, box->isLineBreak(), isFirstOnLine, isLastOnLine, containsStart, containsEnd, boxIsHorizontal, isFixed, containingBlock->isRubyText(), view().pageNumberForBlockProgressionOffset(absRect.x())));
382     }
383 }
384 #endif
385
386 Vector<FloatQuad> RenderText::absoluteQuadsClippedToEllipsis() const
387 {
388     if (auto layout = simpleLineLayout()) {
389         ASSERT(style().textOverflow() != TextOverflowEllipsis);
390         return collectTextAbsoluteQuads(*this, *layout, nullptr);
391     }
392     return m_lineBoxes.absoluteQuads(*this, nullptr, RenderTextLineBoxes::ClipToEllipsis);
393 }
394
395 void RenderText::absoluteQuads(Vector<FloatQuad>& quads, bool* wasFixed) const
396 {
397     if (auto layout = simpleLineLayout()) {
398         quads.appendVector(collectTextAbsoluteQuads(*this, *layout, wasFixed));
399         return;
400     }
401     quads.appendVector(m_lineBoxes.absoluteQuads(*this, wasFixed, RenderTextLineBoxes::NoClipping));
402 }
403
404 Vector<FloatQuad> RenderText::absoluteQuadsForRange(unsigned start, unsigned end, bool useSelectionHeight, bool* wasFixed) const
405 {
406     const_cast<RenderText&>(*this).ensureLineBoxes();
407
408     // Work around signed/unsigned issues. This function takes unsigneds, and is often passed UINT_MAX
409     // to mean "all the way to the end". InlineTextBox coordinates are unsigneds, so changing this 
410     // function to take ints causes various internal mismatches. But selectionRect takes ints, and 
411     // passing UINT_MAX to it causes trouble. Ideally we'd change selectionRect to take unsigneds, but 
412     // that would cause many ripple effects, so for now we'll just clamp our unsigned parameters to INT_MAX.
413     ASSERT(end == UINT_MAX || end <= INT_MAX);
414     ASSERT(start <= INT_MAX);
415     start = std::min(start, static_cast<unsigned>(INT_MAX));
416     end = std::min(end, static_cast<unsigned>(INT_MAX));
417     
418     return m_lineBoxes.absoluteQuadsForRange(*this, start, end, useSelectionHeight, wasFixed);
419 }
420
421 VisiblePosition RenderText::positionForPoint(const LayoutPoint& point, const RenderRegion*)
422 {
423     ensureLineBoxes();
424
425     return m_lineBoxes.positionForPoint(*this, point);
426 }
427
428 LayoutRect RenderText::localCaretRect(InlineBox* inlineBox, int caretOffset, LayoutUnit* extraWidthToEndOfLine)
429 {
430     if (!inlineBox)
431         return LayoutRect();
432
433     InlineTextBox* box = toInlineTextBox(inlineBox);
434     float left = box->positionForOffset(caretOffset);
435     return box->root().computeCaretRect(left, caretWidth, extraWidthToEndOfLine);
436 }
437
438 ALWAYS_INLINE float RenderText::widthFromCache(const Font& f, int start, int len, float xPos, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow* glyphOverflow, const RenderStyle& style) const
439 {
440     if (style.hasTextCombine() && isCombineText()) {
441         const RenderCombineText& combineText = toRenderCombineText(*this);
442         if (combineText.isCombined())
443             return combineText.combinedTextWidth(f);
444     }
445
446     if (f.isFixedPitch() && !f.isSmallCaps() && m_isAllASCII && (!glyphOverflow || !glyphOverflow->computeBounds)) {
447         float monospaceCharacterWidth = f.spaceWidth();
448         float w = 0;
449         bool isSpace;
450         ASSERT(m_text);
451         StringImpl& text = *m_text.impl();
452         for (int i = start; i < start + len; i++) {
453             char c = text[i];
454             if (c <= ' ') {
455                 if (c == ' ' || c == '\n') {
456                     w += monospaceCharacterWidth;
457                     isSpace = true;
458                 } else if (c == '\t') {
459                     if (style.collapseWhiteSpace()) {
460                         w += monospaceCharacterWidth;
461                         isSpace = true;
462                     } else {
463                         w += f.tabWidth(style.tabSize(), xPos + w);
464                         isSpace = false;
465                     }
466                 } else
467                     isSpace = false;
468             } else {
469                 w += monospaceCharacterWidth;
470                 isSpace = false;
471             }
472             if (isSpace && i > start)
473                 w += f.wordSpacing();
474         }
475         return w;
476     }
477
478     TextRun run = RenderBlock::constructTextRun(const_cast<RenderText*>(this), f, this, start, len, style);
479     run.setCharactersLength(textLength() - start);
480     ASSERT(run.charactersLength() >= run.length());
481
482     run.setCharacterScanForCodePath(!canUseSimpleFontCodePath());
483     run.setTabSize(!style.collapseWhiteSpace(), style.tabSize());
484     run.setXPos(xPos);
485     return f.width(run, fallbackFonts, glyphOverflow);
486 }
487
488 void RenderText::trimmedPrefWidths(float leadWidth,
489                                    float& beginMinW, bool& beginWS,
490                                    float& endMinW, bool& endWS,
491                                    bool& hasBreakableChar, bool& hasBreak,
492                                    float& beginMaxW, float& endMaxW,
493                                    float& minW, float& maxW, bool& stripFrontSpaces)
494 {
495     const RenderStyle& style = this->style();
496     bool collapseWhiteSpace = style.collapseWhiteSpace();
497     if (!collapseWhiteSpace)
498         stripFrontSpaces = false;
499
500     if (m_hasTab || preferredLogicalWidthsDirty())
501         computePreferredLogicalWidths(leadWidth);
502
503     beginWS = !stripFrontSpaces && m_hasBeginWS;
504     endWS = m_hasEndWS;
505
506     int len = textLength();
507
508     if (!len || (stripFrontSpaces && text()->containsOnlyWhitespace())) {
509         beginMinW = 0;
510         endMinW = 0;
511         beginMaxW = 0;
512         endMaxW = 0;
513         minW = 0;
514         maxW = 0;
515         hasBreak = false;
516         return;
517     }
518
519     minW = m_minWidth;
520     maxW = m_maxWidth;
521
522     beginMinW = m_beginMinWidth;
523     endMinW = m_endMinWidth;
524
525     hasBreakableChar = m_hasBreakableChar;
526     hasBreak = m_hasBreak;
527
528     ASSERT(m_text);
529     StringImpl& text = *m_text.impl();
530     if (text[0] == ' ' || (text[0] == '\n' && !style.preserveNewline()) || text[0] == '\t') {
531         const Font& font = style.font(); // FIXME: This ignores first-line.
532         if (stripFrontSpaces) {
533             const UChar space = ' ';
534             float spaceWidth = font.width(RenderBlock::constructTextRun(this, font, &space, 1, style));
535             maxW -= spaceWidth;
536         } else
537             maxW += font.wordSpacing();
538     }
539
540     stripFrontSpaces = collapseWhiteSpace && m_hasEndWS;
541
542     if (!style.autoWrap() || minW > maxW)
543         minW = maxW;
544
545     // Compute our max widths by scanning the string for newlines.
546     if (hasBreak) {
547         const Font& f = style.font(); // FIXME: This ignores first-line.
548         bool firstLine = true;
549         beginMaxW = maxW;
550         endMaxW = maxW;
551         for (int i = 0; i < len; i++) {
552             int linelen = 0;
553             while (i + linelen < len && text[i + linelen] != '\n')
554                 linelen++;
555
556             if (linelen) {
557                 endMaxW = widthFromCache(f, i, linelen, leadWidth + endMaxW, 0, 0, style);
558                 if (firstLine) {
559                     firstLine = false;
560                     leadWidth = 0;
561                     beginMaxW = endMaxW;
562                 }
563                 i += linelen;
564             } else if (firstLine) {
565                 beginMaxW = 0;
566                 firstLine = false;
567                 leadWidth = 0;
568             }
569
570             if (i == len - 1)
571                 // A <pre> run that ends with a newline, as in, e.g.,
572                 // <pre>Some text\n\n<span>More text</pre>
573                 endMaxW = 0;
574         }
575     }
576 }
577
578 static inline bool isSpaceAccordingToStyle(UChar c, const RenderStyle& style)
579 {
580     return c == ' ' || (c == noBreakSpace && style.nbspMode() == SPACE);
581 }
582
583 float RenderText::minLogicalWidth() const
584 {
585     if (preferredLogicalWidthsDirty())
586         const_cast<RenderText*>(this)->computePreferredLogicalWidths(0);
587         
588     return m_minWidth;
589 }
590
591 float RenderText::maxLogicalWidth() const
592 {
593     if (preferredLogicalWidthsDirty())
594         const_cast<RenderText*>(this)->computePreferredLogicalWidths(0);
595         
596     return m_maxWidth;
597 }
598
599 void RenderText::computePreferredLogicalWidths(float leadWidth)
600 {
601     HashSet<const SimpleFontData*> fallbackFonts;
602     GlyphOverflow glyphOverflow;
603     computePreferredLogicalWidths(leadWidth, fallbackFonts, glyphOverflow);
604     if (fallbackFonts.isEmpty() && !glyphOverflow.left && !glyphOverflow.right && !glyphOverflow.top && !glyphOverflow.bottom)
605         m_knownToHaveNoOverflowAndNoFallbackFonts = true;
606 }
607
608 static inline float hyphenWidth(RenderText* renderer, const Font& font)
609 {
610     const RenderStyle& style = renderer->style();
611     return font.width(RenderBlock::constructTextRun(renderer, font, style.hyphenString().string(), style));
612 }
613
614 static float maxWordFragmentWidth(RenderText* renderer, const RenderStyle& style, const Font& font, StringView word, int minimumPrefixLength, unsigned minimumSuffixLength, int& suffixStart, HashSet<const SimpleFontData*>& fallbackFonts, GlyphOverflow& glyphOverflow)
615 {
616     suffixStart = 0;
617     if (word.length() <= minimumSuffixLength)
618         return 0;
619
620     Vector<int, 8> hyphenLocations;
621     int hyphenLocation = word.length() - minimumSuffixLength;
622     while ((hyphenLocation = lastHyphenLocation(word, hyphenLocation, style.locale())) >= minimumPrefixLength)
623         hyphenLocations.append(hyphenLocation);
624
625     if (hyphenLocations.isEmpty())
626         return 0;
627
628     hyphenLocations.reverse();
629
630     float minimumFragmentWidthToConsider = font.pixelSize() * 5 / 4 + hyphenWidth(renderer, font);
631     float maxFragmentWidth = 0;
632     for (size_t k = 0; k < hyphenLocations.size(); ++k) {
633         int fragmentLength = hyphenLocations[k] - suffixStart;
634         StringBuilder fragmentWithHyphen;
635         fragmentWithHyphen.append(word.substring(suffixStart, fragmentLength));
636         fragmentWithHyphen.append(style.hyphenString());
637
638         TextRun run = RenderBlock::constructTextRun(renderer, font, fragmentWithHyphen.toString(), style);
639         run.setCharactersLength(fragmentWithHyphen.length());
640         run.setCharacterScanForCodePath(!renderer->canUseSimpleFontCodePath());
641         float fragmentWidth = font.width(run, &fallbackFonts, &glyphOverflow);
642
643         // Narrow prefixes are ignored. See tryHyphenating in RenderBlockLineLayout.cpp.
644         if (fragmentWidth <= minimumFragmentWidthToConsider)
645             continue;
646
647         suffixStart += fragmentLength;
648         maxFragmentWidth = std::max(maxFragmentWidth, fragmentWidth);
649     }
650
651     return maxFragmentWidth;
652 }
653
654 void RenderText::computePreferredLogicalWidths(float leadWidth, HashSet<const SimpleFontData*>& fallbackFonts, GlyphOverflow& glyphOverflow)
655 {
656     ASSERT(m_hasTab || preferredLogicalWidthsDirty() || !m_knownToHaveNoOverflowAndNoFallbackFonts);
657
658     m_minWidth = 0;
659     m_beginMinWidth = 0;
660     m_endMinWidth = 0;
661     m_maxWidth = 0;
662
663     float currMinWidth = 0;
664     float currMaxWidth = 0;
665     m_hasBreakableChar = false;
666     m_hasBreak = false;
667     m_hasTab = false;
668     m_hasBeginWS = false;
669     m_hasEndWS = false;
670
671     const RenderStyle& style = this->style();
672     const Font& font = style.font(); // FIXME: This ignores first-line.
673     float wordSpacing = font.wordSpacing();
674     int len = textLength();
675     LazyLineBreakIterator breakIterator(m_text, style.locale());
676     bool needsWordSpacing = false;
677     bool ignoringSpaces = false;
678     bool isSpace = false;
679     bool firstWord = true;
680     bool firstLine = true;
681     int nextBreakable = -1;
682     int lastWordBoundary = 0;
683
684     // Non-zero only when kerning is enabled, in which case we measure words with their trailing
685     // space, then subtract its width.
686     float wordTrailingSpaceWidth = font.typesettingFeatures() & Kerning ? font.width(RenderBlock::constructTextRun(this, font, &space, 1, style), &fallbackFonts) + wordSpacing : 0;
687
688     // If automatic hyphenation is allowed, we keep track of the width of the widest word (or word
689     // fragment) encountered so far, and only try hyphenating words that are wider.
690     float maxWordWidth = std::numeric_limits<float>::max();
691     int minimumPrefixLength = 0;
692     int minimumSuffixLength = 0;
693     if (style.hyphens() == HyphensAuto && canHyphenate(style.locale())) {
694         maxWordWidth = 0;
695
696         // Map 'hyphenate-limit-{before,after}: auto;' to 2.
697         minimumPrefixLength = style.hyphenationLimitBefore();
698         if (minimumPrefixLength < 0)
699             minimumPrefixLength = 2;
700
701         minimumSuffixLength = style.hyphenationLimitAfter();
702         if (minimumSuffixLength < 0)
703             minimumSuffixLength = 2;
704     }
705
706     int firstGlyphLeftOverflow = -1;
707
708     bool breakNBSP = style.autoWrap() && style.nbspMode() == SPACE;
709     bool breakAll = (style.wordBreak() == BreakAllWordBreak || style.wordBreak() == BreakWordBreak) && style.autoWrap();
710
711     for (int i = 0; i < len; i++) {
712         UChar c = uncheckedCharacterAt(i);
713
714         bool previousCharacterIsSpace = isSpace;
715
716         bool isNewline = false;
717         if (c == '\n') {
718             if (style.preserveNewline()) {
719                 m_hasBreak = true;
720                 isNewline = true;
721                 isSpace = false;
722             } else
723                 isSpace = true;
724         } else if (c == '\t') {
725             if (!style.collapseWhiteSpace()) {
726                 m_hasTab = true;
727                 isSpace = false;
728             } else
729                 isSpace = true;
730         } else
731             isSpace = c == ' ';
732
733         if ((isSpace || isNewline) && !i)
734             m_hasBeginWS = true;
735         if ((isSpace || isNewline) && i == len - 1)
736             m_hasEndWS = true;
737
738         if (!ignoringSpaces && style.collapseWhiteSpace() && previousCharacterIsSpace && isSpace)
739             ignoringSpaces = true;
740
741         if (ignoringSpaces && !isSpace)
742             ignoringSpaces = false;
743
744         // Ignore spaces and soft hyphens
745         if (ignoringSpaces) {
746             ASSERT(lastWordBoundary == i);
747             lastWordBoundary++;
748             continue;
749         } else if (c == softHyphen && style.hyphens() != HyphensNone) {
750             currMaxWidth += widthFromCache(font, lastWordBoundary, i - lastWordBoundary, leadWidth + currMaxWidth, &fallbackFonts, &glyphOverflow, style);
751             if (firstGlyphLeftOverflow < 0)
752                 firstGlyphLeftOverflow = glyphOverflow.left;
753             lastWordBoundary = i + 1;
754             continue;
755         }
756
757         bool hasBreak = breakAll || isBreakable(breakIterator, i, nextBreakable, breakNBSP);
758         bool betweenWords = true;
759         int j = i;
760         while (c != '\n' && !isSpaceAccordingToStyle(c, style) && c != '\t' && (c != softHyphen || style.hyphens() == HyphensNone)) {
761             j++;
762             if (j == len)
763                 break;
764             c = uncheckedCharacterAt(j);
765             if (isBreakable(breakIterator, j, nextBreakable, breakNBSP) && characterAt(j - 1) != softHyphen)
766                 break;
767             if (breakAll) {
768                 betweenWords = false;
769                 break;
770             }
771         }
772
773         int wordLen = j - i;
774         if (wordLen) {
775             bool isSpace = (j < len) && isSpaceAccordingToStyle(c, style);
776             float w;
777             if (wordTrailingSpaceWidth && isSpace)
778                 w = widthFromCache(font, i, wordLen + 1, leadWidth + currMaxWidth, &fallbackFonts, &glyphOverflow, style) - wordTrailingSpaceWidth;
779             else {
780                 w = widthFromCache(font, i, wordLen, leadWidth + currMaxWidth, &fallbackFonts, &glyphOverflow, style);
781                 if (c == softHyphen && style.hyphens() != HyphensNone)
782                     currMinWidth += hyphenWidth(this, font);
783             }
784
785             if (w > maxWordWidth) {
786                 int suffixStart;
787                 float maxFragmentWidth = maxWordFragmentWidth(this, style, font, StringView(m_text).substring(i, wordLen), minimumPrefixLength, minimumSuffixLength, suffixStart, fallbackFonts, glyphOverflow);
788
789                 if (suffixStart) {
790                     float suffixWidth;
791                     if (wordTrailingSpaceWidth && isSpace)
792                         suffixWidth = widthFromCache(font, i + suffixStart, wordLen - suffixStart + 1, leadWidth + currMaxWidth, 0, 0, style) - wordTrailingSpaceWidth;
793                     else
794                         suffixWidth = widthFromCache(font, i + suffixStart, wordLen - suffixStart, leadWidth + currMaxWidth, 0, 0, style);
795
796                     maxFragmentWidth = std::max(maxFragmentWidth, suffixWidth);
797
798                     currMinWidth += maxFragmentWidth - w;
799                     maxWordWidth = std::max(maxWordWidth, maxFragmentWidth);
800                 } else
801                     maxWordWidth = w;
802             }
803
804             if (firstGlyphLeftOverflow < 0)
805                 firstGlyphLeftOverflow = glyphOverflow.left;
806             currMinWidth += w;
807             if (betweenWords) {
808                 if (lastWordBoundary == i)
809                     currMaxWidth += w;
810                 else
811                     currMaxWidth += widthFromCache(font, lastWordBoundary, j - lastWordBoundary, leadWidth + currMaxWidth, &fallbackFonts, &glyphOverflow, style);
812                 lastWordBoundary = j;
813             }
814
815             bool isCollapsibleWhiteSpace = (j < len) && style.isCollapsibleWhiteSpace(c);
816             if (j < len && style.autoWrap())
817                 m_hasBreakableChar = true;
818
819             // Add in wordSpacing to our currMaxWidth, but not if this is the last word on a line or the
820             // last word in the run.
821             if (wordSpacing && (isSpace || isCollapsibleWhiteSpace) && !containsOnlyWhitespace(j, len-j))
822                 currMaxWidth += wordSpacing;
823
824             if (firstWord) {
825                 firstWord = false;
826                 // If the first character in the run is breakable, then we consider ourselves to have a beginning
827                 // minimum width of 0, since a break could occur right before our run starts, preventing us from ever
828                 // being appended to a previous text run when considering the total minimum width of the containing block.
829                 if (hasBreak)
830                     m_hasBreakableChar = true;
831                 m_beginMinWidth = hasBreak ? 0 : currMinWidth;
832             }
833             m_endMinWidth = currMinWidth;
834
835             if (currMinWidth > m_minWidth)
836                 m_minWidth = currMinWidth;
837             currMinWidth = 0;
838
839             i += wordLen - 1;
840         } else {
841             // Nowrap can never be broken, so don't bother setting the
842             // breakable character boolean. Pre can only be broken if we encounter a newline.
843             if (style.autoWrap() || isNewline)
844                 m_hasBreakableChar = true;
845
846             if (currMinWidth > m_minWidth)
847                 m_minWidth = currMinWidth;
848             currMinWidth = 0;
849
850             if (isNewline) { // Only set if preserveNewline was true and we saw a newline.
851                 if (firstLine) {
852                     firstLine = false;
853                     leadWidth = 0;
854                     if (!style.autoWrap())
855                         m_beginMinWidth = currMaxWidth;
856                 }
857
858                 if (currMaxWidth > m_maxWidth)
859                     m_maxWidth = currMaxWidth;
860                 currMaxWidth = 0;
861             } else {
862                 TextRun run = RenderBlock::constructTextRun(this, font, this, i, 1, style);
863                 run.setCharactersLength(len - i);
864                 ASSERT(run.charactersLength() >= run.length());
865                 run.setTabSize(!style.collapseWhiteSpace(), style.tabSize());
866                 run.setXPos(leadWidth + currMaxWidth);
867
868                 currMaxWidth += font.width(run, &fallbackFonts);
869                 glyphOverflow.right = 0;
870                 needsWordSpacing = isSpace && !previousCharacterIsSpace && i == len - 1;
871             }
872             ASSERT(lastWordBoundary == i);
873             lastWordBoundary++;
874         }
875     }
876
877     if (firstGlyphLeftOverflow > 0)
878         glyphOverflow.left = firstGlyphLeftOverflow;
879
880     if ((needsWordSpacing && len > 1) || (ignoringSpaces && !firstWord))
881         currMaxWidth += wordSpacing;
882
883     m_minWidth = std::max(currMinWidth, m_minWidth);
884     m_maxWidth = std::max(currMaxWidth, m_maxWidth);
885
886     if (!style.autoWrap())
887         m_minWidth = m_maxWidth;
888
889     if (style.whiteSpace() == PRE) {
890         if (firstLine)
891             m_beginMinWidth = m_maxWidth;
892         m_endMinWidth = currMaxWidth;
893     }
894
895     setPreferredLogicalWidthsDirty(false);
896 }
897
898 bool RenderText::isAllCollapsibleWhitespace() const
899 {
900     const RenderStyle& style = this->style();
901     unsigned length = textLength();
902     if (is8Bit()) {
903         for (unsigned i = 0; i < length; ++i) {
904             if (!style.isCollapsibleWhiteSpace(characters8()[i]))
905                 return false;
906         }
907         return true;
908     }
909     for (unsigned i = 0; i < length; ++i) {
910         if (!style.isCollapsibleWhiteSpace(characters16()[i]))
911             return false;
912     }
913     return true;
914 }
915     
916 bool RenderText::containsOnlyWhitespace(unsigned from, unsigned len) const
917 {
918     ASSERT(m_text);
919     StringImpl& text = *m_text.impl();
920     unsigned currPos;
921     for (currPos = from;
922          currPos < from + len && (text[currPos] == '\n' || text[currPos] == ' ' || text[currPos] == '\t');
923          currPos++) { }
924     return currPos >= (from + len);
925 }
926
927 IntPoint RenderText::firstRunLocation() const
928 {
929     if (auto* layout = simpleLineLayout())
930         return SimpleLineLayout::computeTextFirstRunLocation(*this, *layout);
931
932     return m_lineBoxes.firstRunLocation();
933 }
934
935 void RenderText::setSelectionState(SelectionState state)
936 {
937     if (state != SelectionNone)
938         ensureLineBoxes();
939
940     RenderObject::setSelectionState(state);
941
942     if (canUpdateSelectionOnRootLineBoxes())
943         m_lineBoxes.setSelectionState(*this, state);
944
945     // The containing block can be null in case of an orphaned tree.
946     RenderBlock* containingBlock = this->containingBlock();
947     if (containingBlock && !containingBlock->isRenderView())
948         containingBlock->setSelectionState(state);
949 }
950
951 void RenderText::setTextWithOffset(const String& text, unsigned offset, unsigned len, bool force)
952 {
953     if (!force && m_text == text)
954         return;
955
956     int delta = text.length() - textLength();
957     unsigned end = len ? offset + len - 1 : offset;
958
959     m_linesDirty = simpleLineLayout() || m_lineBoxes.dirtyRange(*this, offset, end, delta);
960
961     setText(text, force || m_linesDirty);
962 }
963
964 static inline bool isInlineFlowOrEmptyText(const RenderObject* o)
965 {
966     if (o->isRenderInline())
967         return true;
968     if (!o->isText())
969         return false;
970     StringImpl* text = toRenderText(o)->text();
971     if (!text)
972         return true;
973     return !text->length();
974 }
975
976 UChar RenderText::previousCharacter() const
977 {
978     // find previous text renderer if one exists
979     const RenderObject* previousText = this;
980     while ((previousText = previousText->previousInPreOrder()))
981         if (!isInlineFlowOrEmptyText(previousText))
982             break;
983     UChar prev = ' ';
984     if (previousText && previousText->isText())
985         if (StringImpl* previousString = toRenderText(previousText)->text())
986             prev = (*previousString)[previousString->length() - 1];
987     return prev;
988 }
989
990 void applyTextTransform(const RenderStyle& style, String& text, UChar previousCharacter)
991 {
992     switch (style.textTransform()) {
993     case TTNONE:
994         break;
995     case CAPITALIZE:
996         makeCapitalized(&text, previousCharacter);
997         break;
998     case UPPERCASE:
999         text = text.upper(style.locale());
1000         break;
1001     case LOWERCASE:
1002         text = text.lower(style.locale());
1003         break;
1004     }
1005 }
1006
1007 void RenderText::setRenderedText(const String& text)
1008 {
1009     ASSERT(!text.isNull());
1010
1011     String originalText = this->originalText();
1012
1013     m_text = text;
1014
1015     if (m_useBackslashAsYenSymbol)
1016         m_text.replace('\\', yenSign);
1017
1018     ASSERT(m_text);
1019
1020     applyTextTransform(style(), m_text, previousCharacter());
1021
1022     // We use the same characters here as for list markers.
1023     // See the listMarkerText function in RenderListMarker.cpp.
1024     switch (style().textSecurity()) {
1025     case TSNONE:
1026         break;
1027     case TSCIRCLE:
1028 #if PLATFORM(IOS)
1029         secureText(blackCircle);
1030 #else
1031         secureText(whiteBullet);
1032 #endif
1033         break;
1034     case TSDISC:
1035 #if PLATFORM(IOS)
1036         secureText(blackCircle);
1037 #else
1038         secureText(bullet);
1039 #endif
1040         break;
1041     case TSSQUARE:
1042 #if PLATFORM(IOS)
1043         secureText(blackCircle);
1044 #else
1045         secureText(blackSquare);
1046 #endif
1047     }
1048
1049     ASSERT(!m_text.isNull());
1050
1051     m_isAllASCII = m_text.containsOnlyASCII();
1052     m_canUseSimpleFontCodePath = computeCanUseSimpleFontCodePath();
1053
1054     if (m_text != originalText) {
1055         originalTextMap().set(this, originalText);
1056         m_originalTextDiffersFromRendered = true;
1057     } else if (m_originalTextDiffersFromRendered) {
1058         originalTextMap().remove(this);
1059         m_originalTextDiffersFromRendered = false;
1060     }
1061 }
1062
1063 void RenderText::secureText(UChar mask)
1064 {
1065     if (!textLength())
1066         return;
1067
1068     int lastTypedCharacterOffsetToReveal = -1;
1069     String revealedText;
1070     SecureTextTimer* secureTextTimer = gSecureTextTimers ? gSecureTextTimers->get(this) : nullptr;
1071     if (secureTextTimer && secureTextTimer->isActive()) {
1072         lastTypedCharacterOffsetToReveal = secureTextTimer->lastTypedCharacterOffset();
1073         if (lastTypedCharacterOffsetToReveal >= 0)
1074             revealedText = m_text.substring(lastTypedCharacterOffsetToReveal, 1);
1075     }
1076
1077     m_text.fill(mask);
1078     if (lastTypedCharacterOffsetToReveal >= 0) {
1079         m_text.replace(lastTypedCharacterOffsetToReveal, 1, revealedText);
1080         // m_text may be updated later before timer fires. We invalidate the lastTypedCharacterOffset to avoid inconsistency.
1081         secureTextTimer->invalidate();
1082     }
1083 }
1084
1085 void RenderText::setText(const String& text, bool force)
1086 {
1087     ASSERT(!text.isNull());
1088
1089     if (!force && text == originalText())
1090         return;
1091
1092     m_text = text;
1093     if (m_originalTextDiffersFromRendered) {
1094         originalTextMap().remove(this);
1095         m_originalTextDiffersFromRendered = false;
1096     }
1097
1098     setRenderedText(text);
1099
1100     setNeedsLayoutAndPrefWidthsRecalc();
1101     m_knownToHaveNoOverflowAndNoFallbackFonts = false;
1102
1103     if (parent()->isRenderBlockFlow())
1104         toRenderBlockFlow(parent())->invalidateLineLayoutPath();
1105     
1106     if (AXObjectCache* cache = document().existingAXObjectCache())
1107         cache->textChanged(this);
1108 }
1109
1110 String RenderText::textWithoutConvertingBackslashToYenSymbol() const
1111 {
1112     if (!m_useBackslashAsYenSymbol || style().textSecurity() != TSNONE)
1113         return text();
1114
1115     String text = originalText();
1116     applyTextTransform(style(), text, previousCharacter());
1117     return text;
1118 }
1119
1120 void RenderText::dirtyLineBoxes(bool fullLayout)
1121 {
1122     if (fullLayout)
1123         m_lineBoxes.deleteAll();
1124     else if (!m_linesDirty)
1125         m_lineBoxes.dirtyAll();
1126     m_linesDirty = false;
1127 }
1128
1129 std::unique_ptr<InlineTextBox> RenderText::createTextBox()
1130 {
1131     return std::make_unique<InlineTextBox>(*this);
1132 }
1133
1134 void RenderText::positionLineBox(InlineTextBox& textBox)
1135 {
1136     // FIXME: should not be needed!!!
1137     if (!textBox.len()) {
1138         // We want the box to be destroyed.
1139         textBox.removeFromParent();
1140         m_lineBoxes.remove(textBox);
1141         delete &textBox;
1142         return;
1143     }
1144
1145     m_containsReversedText |= !textBox.isLeftToRightDirection();
1146 }
1147
1148 void RenderText::ensureLineBoxes()
1149 {
1150     if (!parent()->isRenderBlockFlow())
1151         return;
1152     toRenderBlockFlow(parent())->ensureLineBoxes();
1153 }
1154
1155 const SimpleLineLayout::Layout* RenderText::simpleLineLayout() const
1156 {
1157     if (!parent()->isRenderBlockFlow())
1158         return nullptr;
1159     return toRenderBlockFlow(parent())->simpleLineLayout();
1160 }
1161
1162 float RenderText::width(unsigned from, unsigned len, float xPos, bool firstLine, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow* glyphOverflow) const
1163 {
1164     if (from >= textLength())
1165         return 0;
1166
1167     if (from + len > textLength())
1168         len = textLength() - from;
1169
1170     const RenderStyle& lineStyle = firstLine ? firstLineStyle() : style();
1171     return width(from, len, lineStyle.font(), xPos, fallbackFonts, glyphOverflow);
1172 }
1173
1174 float RenderText::width(unsigned from, unsigned len, const Font& f, float xPos, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow* glyphOverflow) const
1175 {
1176     ASSERT(from + len <= textLength());
1177     if (!textLength())
1178         return 0;
1179
1180     const RenderStyle& style = this->style();
1181     float w;
1182     if (&f == &style.font()) {
1183         if (!style.preserveNewline() && !from && len == textLength() && (!glyphOverflow || !glyphOverflow->computeBounds)) {
1184             if (fallbackFonts) {
1185                 ASSERT(glyphOverflow);
1186                 if (preferredLogicalWidthsDirty() || !m_knownToHaveNoOverflowAndNoFallbackFonts) {
1187                     const_cast<RenderText*>(this)->computePreferredLogicalWidths(0, *fallbackFonts, *glyphOverflow);
1188                     if (fallbackFonts->isEmpty() && !glyphOverflow->left && !glyphOverflow->right && !glyphOverflow->top && !glyphOverflow->bottom)
1189                         m_knownToHaveNoOverflowAndNoFallbackFonts = true;
1190                 }
1191                 w = m_maxWidth;
1192             } else
1193                 w = maxLogicalWidth();
1194         } else
1195             w = widthFromCache(f, from, len, xPos, fallbackFonts, glyphOverflow, style);
1196     } else {
1197         TextRun run = RenderBlock::constructTextRun(const_cast<RenderText*>(this), f, this, from, len, style);
1198         run.setCharactersLength(textLength() - from);
1199         ASSERT(run.charactersLength() >= run.length());
1200
1201         run.setCharacterScanForCodePath(!canUseSimpleFontCodePath());
1202         run.setTabSize(!style.collapseWhiteSpace(), style.tabSize());
1203         run.setXPos(xPos);
1204         w = f.width(run, fallbackFonts, glyphOverflow);
1205     }
1206
1207     return w;
1208 }
1209
1210 IntRect RenderText::linesBoundingBox() const
1211 {
1212     if (auto layout = simpleLineLayout())
1213         return SimpleLineLayout::computeTextBoundingBox(*this, *layout);
1214
1215     return m_lineBoxes.boundingBox(*this);
1216 }
1217
1218 LayoutRect RenderText::linesVisualOverflowBoundingBox() const
1219 {
1220     ASSERT(!simpleLineLayout());
1221     return m_lineBoxes.visualOverflowBoundingBox(*this);
1222 }
1223
1224 LayoutRect RenderText::clippedOverflowRectForRepaint(const RenderLayerModelObject* repaintContainer) const
1225 {
1226     RenderObject* rendererToRepaint = containingBlock();
1227
1228     // Do not cross self-painting layer boundaries.
1229     RenderObject& enclosingLayerRenderer = enclosingLayer()->renderer();
1230     if (&enclosingLayerRenderer != rendererToRepaint && !rendererToRepaint->isDescendantOf(&enclosingLayerRenderer))
1231         rendererToRepaint = &enclosingLayerRenderer;
1232
1233     // The renderer we chose to repaint may be an ancestor of repaintContainer, but we need to do a repaintContainer-relative repaint.
1234     if (repaintContainer && repaintContainer != rendererToRepaint && !rendererToRepaint->isDescendantOf(repaintContainer))
1235         return repaintContainer->clippedOverflowRectForRepaint(repaintContainer);
1236
1237     return rendererToRepaint->clippedOverflowRectForRepaint(repaintContainer);
1238 }
1239
1240 LayoutRect RenderText::collectSelectionRectsForLineBoxes(const RenderLayerModelObject* repaintContainer, bool clipToVisibleContent, Vector<LayoutRect>* rects)
1241 {
1242     ASSERT(!needsLayout());
1243     ASSERT(!simpleLineLayout());
1244
1245     if (selectionState() == SelectionNone)
1246         return LayoutRect();
1247     RenderBlock* cb = containingBlock();
1248     if (!cb)
1249         return LayoutRect();
1250
1251     // Now calculate startPos and endPos for painting selection.
1252     // We include a selection while endPos > 0
1253     int startPos, endPos;
1254     if (selectionState() == SelectionInside) {
1255         // We are fully selected.
1256         startPos = 0;
1257         endPos = textLength();
1258     } else {
1259         selectionStartEnd(startPos, endPos);
1260         if (selectionState() == SelectionStart)
1261             endPos = textLength();
1262         else if (selectionState() == SelectionEnd)
1263             startPos = 0;
1264     }
1265
1266     if (startPos == endPos)
1267         return IntRect();
1268
1269     LayoutRect resultRect;
1270     if (!rects)
1271         resultRect = m_lineBoxes.selectionRectForRange(startPos, endPos);
1272     else {
1273         m_lineBoxes.collectSelectionRectsForRange(startPos, endPos, *rects);
1274         for (auto& rect : *rects) {
1275             resultRect.unite(rect);
1276             rect = localToContainerQuad(FloatRect(rect), repaintContainer).enclosingBoundingBox();
1277         }
1278     }
1279
1280     if (clipToVisibleContent)
1281         computeRectForRepaint(repaintContainer, resultRect);
1282     else
1283         resultRect = localToContainerQuad(FloatRect(resultRect), repaintContainer).enclosingBoundingBox();
1284
1285     return resultRect;
1286 }
1287
1288 LayoutRect RenderText::collectSelectionRectsForLineBoxes(const RenderLayerModelObject* repaintContainer, bool clipToVisibleContent, Vector<LayoutRect>& rects)
1289 {
1290     return collectSelectionRectsForLineBoxes(repaintContainer, clipToVisibleContent, &rects);
1291 }
1292
1293 LayoutRect RenderText::selectionRectForRepaint(const RenderLayerModelObject* repaintContainer, bool clipToVisibleContent)
1294 {
1295     return collectSelectionRectsForLineBoxes(repaintContainer, clipToVisibleContent, nullptr);
1296 }
1297
1298 int RenderText::caretMinOffset() const
1299 {
1300     if (auto layout = simpleLineLayout())
1301         return SimpleLineLayout::findTextCaretMinimumOffset(*this, *layout);
1302     return m_lineBoxes.caretMinOffset();
1303 }
1304
1305 int RenderText::caretMaxOffset() const
1306 {
1307     if (auto layout = simpleLineLayout())
1308         return SimpleLineLayout::findTextCaretMaximumOffset(*this, *layout);
1309     return m_lineBoxes.caretMaxOffset(*this);
1310 }
1311
1312 unsigned RenderText::countRenderedCharacterOffsetsUntil(unsigned offset) const
1313 {
1314     ASSERT(!simpleLineLayout());
1315     return m_lineBoxes.countCharacterOffsetsUntil(offset);
1316 }
1317
1318 bool RenderText::containsRenderedCharacterOffset(unsigned offset) const
1319 {
1320     ASSERT(!simpleLineLayout());
1321     return m_lineBoxes.containsOffset(*this, offset, RenderTextLineBoxes::CharacterOffset);
1322 }
1323
1324 bool RenderText::containsCaretOffset(unsigned offset) const
1325 {
1326     if (auto layout = simpleLineLayout())
1327         return SimpleLineLayout::containsTextCaretOffset(*this, *layout, offset);
1328     return m_lineBoxes.containsOffset(*this, offset, RenderTextLineBoxes::CaretOffset);
1329 }
1330
1331 bool RenderText::hasRenderedText() const
1332 {
1333     if (auto layout = simpleLineLayout())
1334         return SimpleLineLayout::isTextRendered(*this, *layout);
1335     return m_lineBoxes.hasRenderedText();
1336 }
1337
1338 int RenderText::previousOffset(int current) const
1339 {
1340     if (isAllASCII() || m_text.is8Bit())
1341         return current - 1;
1342
1343     StringImpl* textImpl = m_text.impl();
1344     TextBreakIterator* iterator = cursorMovementIterator(StringView(textImpl->characters16(), textImpl->length()));
1345     if (!iterator)
1346         return current - 1;
1347
1348     long result = textBreakPreceding(iterator, current);
1349     if (result == TextBreakDone)
1350         result = current - 1;
1351
1352
1353     return result;
1354 }
1355
1356 #if PLATFORM(COCOA) || PLATFORM(EFL)
1357
1358 #define HANGUL_CHOSEONG_START (0x1100)
1359 #define HANGUL_CHOSEONG_END (0x115F)
1360 #define HANGUL_JUNGSEONG_START (0x1160)
1361 #define HANGUL_JUNGSEONG_END (0x11A2)
1362 #define HANGUL_JONGSEONG_START (0x11A8)
1363 #define HANGUL_JONGSEONG_END (0x11F9)
1364 #define HANGUL_SYLLABLE_START (0xAC00)
1365 #define HANGUL_SYLLABLE_END (0xD7AF)
1366 #define HANGUL_JONGSEONG_COUNT (28)
1367
1368 enum HangulState {
1369     HangulStateL,
1370     HangulStateV,
1371     HangulStateT,
1372     HangulStateLV,
1373     HangulStateLVT,
1374     HangulStateBreak
1375 };
1376
1377 inline bool isHangulLVT(UChar32 character)
1378 {
1379     return (character - HANGUL_SYLLABLE_START) % HANGUL_JONGSEONG_COUNT;
1380 }
1381
1382 inline bool isMark(UChar32 c)
1383 {
1384     int8_t charType = u_charType(c);
1385     return charType == U_NON_SPACING_MARK || charType == U_ENCLOSING_MARK || charType == U_COMBINING_SPACING_MARK;
1386 }
1387
1388 inline bool isRegionalIndicator(UChar32 c)
1389 {
1390     // National flag emoji each consists of a pair of regional indicator symbols.
1391     return 0x1F1E6 <= c && c <= 0x1F1FF;
1392 }
1393
1394 #endif
1395
1396 int RenderText::previousOffsetForBackwardDeletion(int current) const
1397 {
1398 #if PLATFORM(COCOA) || PLATFORM(EFL)
1399     ASSERT(m_text);
1400     StringImpl& text = *m_text.impl();
1401     UChar32 character;
1402     bool sawRegionalIndicator = false;
1403     while (current > 0) {
1404         if (U16_IS_TRAIL(text[--current]))
1405             --current;
1406         if (current < 0)
1407             break;
1408
1409         UChar32 character = text.characterStartingAt(current);
1410
1411         if (sawRegionalIndicator) {
1412             // We don't check if the pair of regional indicator symbols before current position can actually be combined
1413             // into a flag, and just delete it. This may not agree with how the pair is rendered in edge cases,
1414             // but is good enough in practice.
1415             if (isRegionalIndicator(character))
1416                 break;
1417             // Don't delete a preceding character that isn't a regional indicator symbol.
1418             U16_FWD_1_UNSAFE(text, current);
1419         }
1420
1421         // We don't combine characters in Armenian ... Limbu range for backward deletion.
1422         if ((character >= 0x0530) && (character < 0x1950))
1423             break;
1424
1425         if (isRegionalIndicator(character)) {
1426             sawRegionalIndicator = true;
1427             continue;
1428         }
1429
1430         if (!isMark(character) && (character != 0xFF9E) && (character != 0xFF9F))
1431             break;
1432     }
1433
1434     if (current <= 0)
1435         return current;
1436
1437     // Hangul
1438     character = text.characterStartingAt(current);
1439     if (((character >= HANGUL_CHOSEONG_START) && (character <= HANGUL_JONGSEONG_END)) || ((character >= HANGUL_SYLLABLE_START) && (character <= HANGUL_SYLLABLE_END))) {
1440         HangulState state;
1441
1442         if (character < HANGUL_JUNGSEONG_START)
1443             state = HangulStateL;
1444         else if (character < HANGUL_JONGSEONG_START)
1445             state = HangulStateV;
1446         else if (character < HANGUL_SYLLABLE_START)
1447             state = HangulStateT;
1448         else
1449             state = isHangulLVT(character) ? HangulStateLVT : HangulStateLV;
1450
1451         while (current > 0 && ((character = text.characterStartingAt(current - 1)) >= HANGUL_CHOSEONG_START) && (character <= HANGUL_SYLLABLE_END) && ((character <= HANGUL_JONGSEONG_END) || (character >= HANGUL_SYLLABLE_START))) {
1452             switch (state) {
1453             case HangulStateV:
1454                 if (character <= HANGUL_CHOSEONG_END)
1455                     state = HangulStateL;
1456                 else if ((character >= HANGUL_SYLLABLE_START) && (character <= HANGUL_SYLLABLE_END) && !isHangulLVT(character))
1457                     state = HangulStateLV;
1458                 else if (character > HANGUL_JUNGSEONG_END)
1459                     state = HangulStateBreak;
1460                 break;
1461             case HangulStateT:
1462                 if ((character >= HANGUL_JUNGSEONG_START) && (character <= HANGUL_JUNGSEONG_END))
1463                     state = HangulStateV;
1464                 else if ((character >= HANGUL_SYLLABLE_START) && (character <= HANGUL_SYLLABLE_END))
1465                     state = (isHangulLVT(character) ? HangulStateLVT : HangulStateLV);
1466                 else if (character < HANGUL_JUNGSEONG_START)
1467                     state = HangulStateBreak;
1468                 break;
1469             default:
1470                 state = (character < HANGUL_JUNGSEONG_START) ? HangulStateL : HangulStateBreak;
1471                 break;
1472             }
1473             if (state == HangulStateBreak)
1474                 break;
1475
1476             --current;
1477         }
1478     }
1479
1480     return current;
1481 #else
1482     // Platforms other than Mac delete by one code point.
1483     if (U16_IS_TRAIL(m_text[--current]))
1484         --current;
1485     if (current < 0)
1486         current = 0;
1487     return current;
1488 #endif
1489 }
1490
1491 int RenderText::nextOffset(int current) const
1492 {
1493     if (isAllASCII() || m_text.is8Bit())
1494         return current + 1;
1495
1496     StringImpl* textImpl = m_text.impl();
1497     TextBreakIterator* iterator = cursorMovementIterator(StringView(textImpl->characters16(), textImpl->length()));
1498     if (!iterator)
1499         return current + 1;
1500
1501     long result = textBreakFollowing(iterator, current);
1502     if (result == TextBreakDone)
1503         result = current + 1;
1504
1505     return result;
1506 }
1507
1508 bool RenderText::computeCanUseSimpleFontCodePath() const
1509 {
1510     if (isAllASCII() || m_text.is8Bit())
1511         return true;
1512     return Font::characterRangeCodePath(characters16(), length()) == Font::Simple;
1513 }
1514
1515 void RenderText::momentarilyRevealLastTypedCharacter(unsigned lastTypedCharacterOffset)
1516 {
1517     if (!gSecureTextTimers)
1518         gSecureTextTimers = new SecureTextTimerMap;
1519
1520     SecureTextTimer* secureTextTimer = gSecureTextTimers->get(this);
1521     if (!secureTextTimer) {
1522         secureTextTimer = new SecureTextTimer(this);
1523         gSecureTextTimers->add(this, secureTextTimer);
1524     }
1525     secureTextTimer->restartWithNewText(lastTypedCharacterOffset);
1526 }
1527
1528 StringView RenderText::stringView(int start, int stop) const
1529 {
1530     ASSERT(static_cast<unsigned>(start) <= length());
1531     ASSERT(static_cast<unsigned>(stop) <= length());
1532     ASSERT(start <= stop);
1533     ASSERT(start >= 0);
1534     ASSERT(stop >= 0);
1535     if (is8Bit())
1536         return StringView(characters8() + start, stop - start);
1537     return StringView(characters16() + start, stop - start);
1538 }
1539
1540 } // namespace WebCore