Remove redundant RenderObject::selectionRoot and dependencies
[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-2007, 2013-2015 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 "BreakLines.h"
30 #include "BreakingContext.h"
31 #include "CharacterProperties.h"
32 #include "DocumentMarkerController.h"
33 #include "EllipsisBox.h"
34 #include "FloatQuad.h"
35 #include "Frame.h"
36 #include "FrameView.h"
37 #include "Hyphenation.h"
38 #include "InlineTextBox.h"
39 #include "Range.h"
40 #include "RenderBlock.h"
41 #include "RenderCombineText.h"
42 #include "RenderInline.h"
43 #include "RenderLayer.h"
44 #include "RenderView.h"
45 #include "RenderedDocumentMarker.h"
46 #include "Settings.h"
47 #include "SimpleLineLayoutFunctions.h"
48 #include "Text.h"
49 #include <wtf/text/TextBreakIterator.h>
50 #include "TextResourceDecoder.h"
51 #include "VisiblePosition.h"
52 #include <wtf/NeverDestroyed.h>
53 #include <wtf/text/StringBuffer.h>
54 #include <wtf/text/StringBuilder.h>
55 #include <wtf/unicode/CharacterNames.h>
56
57 #if PLATFORM(IOS)
58 #include "Document.h"
59 #include "EditorClient.h"
60 #include "LogicalSelectionOffsetCaches.h"
61 #include "Page.h"
62 #include "SelectionRect.h"
63 #endif
64
65 using namespace WTF;
66 using namespace Unicode;
67
68 namespace WebCore {
69
70 struct SameSizeAsRenderText : public RenderObject {
71     void* pointers[2];
72     uint32_t bitfields : 16;
73 #if ENABLE(TEXT_AUTOSIZING)
74     float candidateTextSize;
75 #endif
76     float widths[4];
77     String text;
78 };
79
80 COMPILE_ASSERT(sizeof(RenderText) == sizeof(SameSizeAsRenderText), RenderText_should_stay_small);
81
82 class SecureTextTimer final : private TimerBase {
83     WTF_MAKE_FAST_ALLOCATED;
84 public:
85     explicit SecureTextTimer(RenderText&);
86     void restart(unsigned offsetAfterLastTypedCharacter);
87
88     unsigned takeOffsetAfterLastTypedCharacter();
89
90 private:
91     void fired() override;
92     RenderText& m_renderer;
93     unsigned m_offsetAfterLastTypedCharacter { 0 };
94 };
95
96 typedef HashMap<RenderText*, std::unique_ptr<SecureTextTimer>> SecureTextTimerMap;
97
98 static SecureTextTimerMap& secureTextTimers()
99 {
100     static NeverDestroyed<SecureTextTimerMap> map;
101     return map.get();
102 }
103
104 inline SecureTextTimer::SecureTextTimer(RenderText& renderer)
105     : m_renderer(renderer)
106 {
107 }
108
109 inline void SecureTextTimer::restart(unsigned offsetAfterLastTypedCharacter)
110 {
111     m_offsetAfterLastTypedCharacter = offsetAfterLastTypedCharacter;
112     startOneShot(1_s * m_renderer.settings().passwordEchoDurationInSeconds());
113 }
114
115 inline unsigned SecureTextTimer::takeOffsetAfterLastTypedCharacter()
116 {
117     unsigned offset = m_offsetAfterLastTypedCharacter;
118     m_offsetAfterLastTypedCharacter = 0;
119     return offset;
120 }
121
122 void SecureTextTimer::fired()
123 {
124     ASSERT(secureTextTimers().get(&m_renderer) == this);
125     m_offsetAfterLastTypedCharacter = 0;
126     m_renderer.setText(m_renderer.text(), true /* forcing setting text as it may be masked later */);
127 }
128
129 static HashMap<const RenderText*, String>& originalTextMap()
130 {
131     static NeverDestroyed<HashMap<const RenderText*, String>> map;
132     return map;
133 }
134
135 void makeCapitalized(String* string, UChar previous)
136 {
137     // FIXME: Need to change this to use u_strToTitle instead of u_totitle and to consider locale.
138
139     if (string->isNull())
140         return;
141
142     unsigned length = string->length();
143     const StringImpl& stringImpl = *string->impl();
144
145     if (length >= std::numeric_limits<unsigned>::max())
146         CRASH();
147
148     StringBuffer<UChar> stringWithPrevious(length + 1);
149     stringWithPrevious[0] = previous == noBreakSpace ? ' ' : previous;
150     for (unsigned i = 1; i < length + 1; i++) {
151         // Replace &nbsp with a real space since ICU no longer treats &nbsp as a word separator.
152         if (stringImpl[i - 1] == noBreakSpace)
153             stringWithPrevious[i] = ' ';
154         else
155             stringWithPrevious[i] = stringImpl[i - 1];
156     }
157
158     UBreakIterator* boundary = wordBreakIterator(StringView(stringWithPrevious.characters(), length + 1));
159     if (!boundary)
160         return;
161
162     StringBuilder result;
163     result.reserveCapacity(length);
164
165     int32_t endOfWord;
166     int32_t startOfWord = ubrk_first(boundary);
167     for (endOfWord = ubrk_next(boundary); endOfWord != UBRK_DONE; startOfWord = endOfWord, endOfWord = ubrk_next(boundary)) {
168         if (startOfWord) // Ignore first char of previous string
169             result.append(stringImpl[startOfWord - 1] == noBreakSpace ? noBreakSpace : u_totitle(stringWithPrevious[startOfWord]));
170         for (int i = startOfWord + 1; i < endOfWord; i++)
171             result.append(stringImpl[i - 1]);
172     }
173
174     *string = result.toString();
175 }
176
177 inline RenderText::RenderText(Node& node, const String& text)
178     : RenderObject(node)
179     , m_hasTab(false)
180     , m_linesDirty(false)
181     , m_containsReversedText(false)
182     , m_isAllASCII(text.containsOnlyASCII())
183     , m_knownToHaveNoOverflowAndNoFallbackFonts(false)
184     , m_useBackslashAsYenSymbol(false)
185     , m_originalTextDiffersFromRendered(false)
186 #if ENABLE(TEXT_AUTOSIZING)
187     , m_candidateComputedTextSize(0)
188 #endif
189     , m_minWidth(-1)
190     , m_maxWidth(-1)
191     , m_beginMinWidth(0)
192     , m_endMinWidth(0)
193     , m_text(text)
194 {
195     ASSERT(!m_text.isNull());
196     setIsText();
197     m_canUseSimpleFontCodePath = computeCanUseSimpleFontCodePath();
198     view().frameView().incrementVisuallyNonEmptyCharacterCount(textLength());
199 }
200
201 RenderText::RenderText(Text& textNode, const String& text)
202     : RenderText(static_cast<Node&>(textNode), text)
203 {
204 }
205
206 RenderText::RenderText(Document& document, const String& text)
207     : RenderText(static_cast<Node&>(document), text)
208 {
209 }
210
211 RenderText::~RenderText()
212 {
213     // Do not add any code here. Add it to willBeDestroyed() instead.
214     ASSERT(!originalTextMap().contains(this));
215 }
216
217 const char* RenderText::renderName() const
218 {
219     return "RenderText";
220 }
221
222 Text* RenderText::textNode() const
223 {
224     return downcast<Text>(RenderObject::node());
225 }
226
227 bool RenderText::isTextFragment() const
228 {
229     return false;
230 }
231
232 bool RenderText::computeUseBackslashAsYenSymbol() const
233 {
234     const RenderStyle& style = this->style();
235     const auto& fontDescription = style.fontDescription();
236     if (style.fontCascade().useBackslashAsYenSymbol())
237         return true;
238     if (fontDescription.isSpecifiedFont())
239         return false;
240     const TextEncoding* encoding = document().decoder() ? &document().decoder()->encoding() : 0;
241     if (encoding && encoding->backslashAsCurrencySymbol() != '\\')
242         return true;
243     return false;
244 }
245
246 void RenderText::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
247 {
248     // There is no need to ever schedule repaints from a style change of a text run, since
249     // we already did this for the parent of the text run.
250     // We do have to schedule layouts, though, since a style change can force us to
251     // need to relayout.
252     if (diff == StyleDifferenceLayout) {
253         setNeedsLayoutAndPrefWidthsRecalc();
254         m_knownToHaveNoOverflowAndNoFallbackFonts = false;
255     }
256
257     const RenderStyle& newStyle = style();
258     bool needsResetText = false;
259     if (!oldStyle) {
260         m_useBackslashAsYenSymbol = computeUseBackslashAsYenSymbol();
261         needsResetText = m_useBackslashAsYenSymbol;
262         // It should really be computed in the c'tor, but during construction we don't have parent yet -and RenderText style == parent()->style()
263         m_canUseSimplifiedTextMeasuring = computeCanUseSimplifiedTextMeasuring();
264     } else if (oldStyle->fontCascade().useBackslashAsYenSymbol() != newStyle.fontCascade().useBackslashAsYenSymbol()) {
265         m_useBackslashAsYenSymbol = computeUseBackslashAsYenSymbol();
266         needsResetText = true;
267     }
268
269     ETextTransform oldTransform = oldStyle ? oldStyle->textTransform() : TTNONE;
270     ETextSecurity oldSecurity = oldStyle ? oldStyle->textSecurity() : TSNONE;
271     if (needsResetText || oldTransform != newStyle.textTransform() || oldSecurity != newStyle.textSecurity())
272         RenderText::setText(originalText(), true);
273 }
274
275 void RenderText::removeAndDestroyTextBoxes()
276 {
277     if (!renderTreeBeingDestroyed())
278         m_lineBoxes.removeAllFromParent(*this);
279 #if !ASSERT_WITH_SECURITY_IMPLICATION_DISABLED
280     else
281         m_lineBoxes.invalidateParentChildLists();
282 #endif
283     m_lineBoxes.deleteAll();
284 }
285
286 void RenderText::willBeDestroyed()
287 {
288     secureTextTimers().remove(this);
289
290     removeAndDestroyTextBoxes();
291
292     if (m_originalTextDiffersFromRendered)
293         originalTextMap().remove(this);
294
295     RenderObject::willBeDestroyed();
296 }
297
298 void RenderText::deleteLineBoxesBeforeSimpleLineLayout()
299 {
300     m_lineBoxes.deleteAll();
301 }
302
303 String RenderText::originalText() const
304 {
305     return m_originalTextDiffersFromRendered ? originalTextMap().get(this) : m_text;
306 }
307
308 void RenderText::absoluteRects(Vector<IntRect>& rects, const LayoutPoint& accumulatedOffset) const
309 {
310     if (auto* layout = simpleLineLayout()) {
311         rects.appendVector(SimpleLineLayout::collectAbsoluteRects(*this, *layout, accumulatedOffset));
312         return;
313     }
314     rects.appendVector(m_lineBoxes.absoluteRects(accumulatedOffset));
315 }
316
317 Vector<IntRect> RenderText::absoluteRectsForRange(unsigned start, unsigned end, bool useSelectionHeight, bool* wasFixed) const
318 {
319     const_cast<RenderText&>(*this).ensureLineBoxes();
320
321     // Work around signed/unsigned issues. This function takes unsigneds, and is often passed UINT_MAX
322     // to mean "all the way to the end". InlineTextBox coordinates are unsigneds, so changing this 
323     // function to take ints causes various internal mismatches. But selectionRect takes ints, and 
324     // passing UINT_MAX to it causes trouble. Ideally we'd change selectionRect to take unsigneds, but 
325     // that would cause many ripple effects, so for now we'll just clamp our unsigned parameters to INT_MAX.
326     ASSERT(end == UINT_MAX || end <= INT_MAX);
327     ASSERT(start <= INT_MAX);
328     start = std::min(start, static_cast<unsigned>(INT_MAX));
329     end = std::min(end, static_cast<unsigned>(INT_MAX));
330     
331     return m_lineBoxes.absoluteRectsForRange(*this, start, end, useSelectionHeight, wasFixed);
332 }
333
334 #if PLATFORM(IOS)
335 // This function is similar in spirit to addLineBoxRects, but returns rectangles
336 // which are annotated with additional state which helps the iPhone draw selections in its unique way.
337 // Full annotations are added in this class.
338 void RenderText::collectSelectionRects(Vector<SelectionRect>& rects, unsigned start, unsigned end)
339 {
340     // FIXME: Work around signed/unsigned issues. This function takes unsigneds, and is often passed UINT_MAX
341     // to mean "all the way to the end". InlineTextBox coordinates are unsigneds, so changing this 
342     // function to take ints causes various internal mismatches. But selectionRect takes ints, and 
343     // passing UINT_MAX to it causes trouble. Ideally we'd change selectionRect to take unsigneds, but 
344     // that would cause many ripple effects, so for now we'll just clamp our unsigned parameters to INT_MAX.
345     ASSERT(end == std::numeric_limits<unsigned>::max() || end <= std::numeric_limits<int>::max());
346     ASSERT(start <= std::numeric_limits<int>::max());
347     start = std::min(start, static_cast<unsigned>(std::numeric_limits<int>::max()));
348     end = std::min(end, static_cast<unsigned>(std::numeric_limits<int>::max()));
349
350     for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox()) {
351         LayoutRect rect;
352         // Note, box->end() returns the index of the last character, not the index past it.
353         if (start <= box->start() && box->end() < end)
354             rect = box->localSelectionRect(start, end);
355         else {
356             unsigned realEnd = std::min(box->end() + 1, end);
357             rect = box->localSelectionRect(start, realEnd);
358             if (rect.isEmpty())
359                 continue;
360         }
361
362         if (box->root().isFirstAfterPageBreak()) {
363             if (box->isHorizontal())
364                 rect.shiftYEdgeTo(box->root().lineTopWithLeading());
365             else
366                 rect.shiftXEdgeTo(box->root().lineTopWithLeading());
367         }
368
369         RenderBlock* containingBlock = this->containingBlock();
370         // Map rect, extended left to leftOffset, and right to rightOffset, through transforms to get minX and maxX.
371         LogicalSelectionOffsetCaches cache(*containingBlock);
372         LayoutUnit leftOffset = containingBlock->logicalLeftSelectionOffset(*containingBlock, box->logicalTop(), cache);
373         LayoutUnit rightOffset = containingBlock->logicalRightSelectionOffset(*containingBlock, box->logicalTop(), cache);
374         LayoutRect extentsRect = rect;
375         if (box->isHorizontal()) {
376             extentsRect.setX(leftOffset);
377             extentsRect.setWidth(rightOffset - leftOffset);
378         } else {
379             extentsRect.setY(leftOffset);
380             extentsRect.setHeight(rightOffset - leftOffset);
381         }
382         extentsRect = localToAbsoluteQuad(FloatRect(extentsRect)).enclosingBoundingBox();
383         if (!box->isHorizontal())
384             extentsRect = extentsRect.transposedRect();
385         bool isFirstOnLine = !box->previousOnLineExists();
386         bool isLastOnLine = !box->nextOnLineExists();
387         if (containingBlock->isRubyBase() || containingBlock->isRubyText())
388             isLastOnLine = !containingBlock->containingBlock()->inlineBoxWrapper()->nextOnLineExists();
389
390         bool containsStart = box->start() <= start && box->end() + 1 >= start;
391         bool containsEnd = box->start() <= end && box->end() + 1 >= end;
392
393         bool isFixed = false;
394         IntRect absRect = localToAbsoluteQuad(FloatRect(rect), UseTransforms, &isFixed).enclosingBoundingBox();
395         bool boxIsHorizontal = !box->isSVGInlineTextBox() ? box->isHorizontal() : !style().isVerticalWritingMode();
396         // If the containing block is an inline element, we want to check the inlineBoxWrapper orientation
397         // to determine the orientation of the block. In this case we also use the inlineBoxWrapper to
398         // determine if the element is the last on the line.
399         if (containingBlock->inlineBoxWrapper()) {
400             if (containingBlock->inlineBoxWrapper()->isHorizontal() != boxIsHorizontal) {
401                 boxIsHorizontal = containingBlock->inlineBoxWrapper()->isHorizontal();
402                 isLastOnLine = !containingBlock->inlineBoxWrapper()->nextOnLineExists();
403             }
404         }
405
406         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())));
407     }
408 }
409 #endif
410
411 Vector<FloatQuad> RenderText::absoluteQuadsClippedToEllipsis() const
412 {
413     if (auto* layout = simpleLineLayout()) {
414         ASSERT(style().textOverflow() != TextOverflowEllipsis);
415         return SimpleLineLayout::collectAbsoluteQuads(*this, *layout, nullptr);
416     }
417     return m_lineBoxes.absoluteQuads(*this, nullptr, RenderTextLineBoxes::ClipToEllipsis);
418 }
419
420 void RenderText::absoluteQuads(Vector<FloatQuad>& quads, bool* wasFixed) const
421 {
422     if (auto* layout = simpleLineLayout()) {
423         quads.appendVector(SimpleLineLayout::collectAbsoluteQuads(*this, *layout, wasFixed));
424         return;
425     }
426     quads.appendVector(m_lineBoxes.absoluteQuads(*this, wasFixed, RenderTextLineBoxes::NoClipping));
427 }
428
429 Vector<FloatQuad> RenderText::absoluteQuadsForRange(unsigned start, unsigned end, bool useSelectionHeight, bool* wasFixed) const
430 {
431     // Work around signed/unsigned issues. This function takes unsigneds, and is often passed UINT_MAX
432     // to mean "all the way to the end". InlineTextBox coordinates are unsigneds, so changing this
433     // function to take ints causes various internal mismatches. But selectionRect takes ints, and
434     // passing UINT_MAX to it causes trouble. Ideally we'd change selectionRect to take unsigneds, but
435     // that would cause many ripple effects, so for now we'll just clamp our unsigned parameters to INT_MAX.
436     ASSERT(end == UINT_MAX || end <= INT_MAX);
437     ASSERT(start <= INT_MAX);
438     start = std::min(start, static_cast<unsigned>(INT_MAX));
439     end = std::min(end, static_cast<unsigned>(INT_MAX));
440     if (simpleLineLayout() && !useSelectionHeight)
441         return collectAbsoluteQuadsForRange(*this, start, end, *simpleLineLayout(), wasFixed);
442     const_cast<RenderText&>(*this).ensureLineBoxes();
443     return m_lineBoxes.absoluteQuadsForRange(*this, start, end, useSelectionHeight, wasFixed);
444 }
445
446 Position RenderText::positionForPoint(const LayoutPoint& point)
447 {
448     if (simpleLineLayout() && parent()->firstChild() == parent()->lastChild()) {
449         auto offset = SimpleLineLayout::textOffsetForPoint(point, *this, *simpleLineLayout());
450         // Did not find a valid offset. Fall back to the normal line layout based Position.
451         if (offset == textLength())
452             return positionForPoint(point, nullptr).deepEquivalent();
453         auto position = Position(textNode(), offset);
454         ASSERT(position == positionForPoint(point, nullptr).deepEquivalent());
455         return position;
456     }
457     return positionForPoint(point, nullptr).deepEquivalent();
458 }
459
460 VisiblePosition RenderText::positionForPoint(const LayoutPoint& point, const RenderFragmentContainer*)
461 {
462     ensureLineBoxes();
463     return m_lineBoxes.positionForPoint(*this, point);
464 }
465
466 LayoutRect RenderText::localCaretRect(InlineBox* inlineBox, unsigned caretOffset, LayoutUnit* extraWidthToEndOfLine)
467 {
468     if (!inlineBox)
469         return LayoutRect();
470
471     auto& box = downcast<InlineTextBox>(*inlineBox);
472     float left = box.positionForOffset(caretOffset);
473     return box.root().computeCaretRect(left, caretWidth, extraWidthToEndOfLine);
474 }
475
476 ALWAYS_INLINE float RenderText::widthFromCache(const FontCascade& f, unsigned start, unsigned len, float xPos, HashSet<const Font*>* fallbackFonts, GlyphOverflow* glyphOverflow, const RenderStyle& style) const
477 {
478     if (style.hasTextCombine() && is<RenderCombineText>(*this)) {
479         const RenderCombineText& combineText = downcast<RenderCombineText>(*this);
480         if (combineText.isCombined())
481             return combineText.combinedTextWidth(f);
482     }
483
484     if (f.isFixedPitch() && f.fontDescription().variantSettings().isAllNormal() && m_isAllASCII && (!glyphOverflow || !glyphOverflow->computeBounds)) {
485         float monospaceCharacterWidth = f.spaceWidth();
486         float w = 0;
487         bool isSpace;
488         ASSERT(m_text);
489         StringImpl& text = *m_text.impl();
490         for (unsigned i = start; i < start + len; i++) {
491             char c = text[i];
492             if (c <= ' ') {
493                 if (c == ' ' || c == '\n') {
494                     w += monospaceCharacterWidth;
495                     isSpace = true;
496                 } else if (c == '\t') {
497                     if (style.collapseWhiteSpace()) {
498                         w += monospaceCharacterWidth;
499                         isSpace = true;
500                     } else {
501                         w += f.tabWidth(style.tabSize(), xPos + w);
502                         isSpace = false;
503                     }
504                 } else
505                     isSpace = false;
506             } else {
507                 w += monospaceCharacterWidth;
508                 isSpace = false;
509             }
510             if (isSpace && i > start)
511                 w += f.wordSpacing();
512         }
513         return w;
514     }
515
516     TextRun run = RenderBlock::constructTextRun(*this, start, len, style);
517     run.setCharacterScanForCodePath(!canUseSimpleFontCodePath());
518     run.setTabSize(!style.collapseWhiteSpace(), style.tabSize());
519     run.setXPos(xPos);
520     return f.width(run, fallbackFonts, glyphOverflow);
521 }
522
523 inline bool isHangablePunctuationAtLineStart(UChar c)
524 {
525     return U_GET_GC_MASK(c) & (U_GC_PS_MASK | U_GC_PI_MASK | U_GC_PF_MASK);
526 }
527
528 inline bool isHangablePunctuationAtLineEnd(UChar c)
529 {
530     return U_GET_GC_MASK(c) & (U_GC_PE_MASK | U_GC_PI_MASK | U_GC_PF_MASK);
531 }
532
533 float RenderText::hangablePunctuationStartWidth(unsigned index) const
534 {
535     unsigned len = textLength();
536     if (!len || index >= len)
537         return 0;
538
539     ASSERT(m_text);
540     StringImpl& text = *m_text.impl();
541     
542     if (!isHangablePunctuationAtLineStart(text[index]))
543         return 0;
544
545     const RenderStyle& style = this->style();
546     const FontCascade& font = style.fontCascade();
547         
548     return widthFromCache(font, index, 1, 0, 0, 0, style);
549 }
550
551 float RenderText::hangablePunctuationEndWidth(unsigned index) const
552 {
553     unsigned len = textLength();
554     if (!len || index >= len)
555         return 0;
556     
557     ASSERT(m_text);
558     StringImpl& text = *m_text.impl();
559
560     if (!isHangablePunctuationAtLineEnd(text[index]))
561         return 0;
562     
563     const RenderStyle& style = this->style();
564     const FontCascade& font = style.fontCascade();
565     
566     return widthFromCache(font, index, 1, 0, 0, 0, style);
567 }
568
569 bool RenderText::isHangableStopOrComma(UChar c) const
570 {
571     return c == 0x002C || c == 0x002E || c == 0x060C || c == 0x06D4 || c == 0x3001
572         || c == 0x3002 || c == 0xFF0C || c == 0xFF0E || c == 0xFE50 || c == 0xFE51
573         || c == 0xFE52 || c == 0xFF61 || c == 0xFF64;
574 }
575
576 unsigned RenderText::firstCharacterIndexStrippingSpaces() const
577 {
578     if (!style().collapseWhiteSpace())
579         return 0;
580     
581     ASSERT(m_text);
582     StringImpl& text = *m_text.impl();
583     
584     unsigned i = 0;
585     for ( ; i < textLength(); ++i) {
586         if (text[i] != ' ' && (text[i] != '\n' || style().preserveNewline()) && text[i] != '\t')
587             break;
588     }
589     return i;
590 }
591
592 unsigned RenderText::lastCharacterIndexStrippingSpaces() const
593 {
594     if (!textLength())
595         return 0;
596
597     if (!style().collapseWhiteSpace())
598         return textLength() - 1;
599     
600     ASSERT(m_text);
601     StringImpl& text = *m_text.impl();
602     
603     int i = textLength() - 1;
604     for ( ; i  >= 0; --i) {
605         if (text[i] != ' ' && (text[i] != '\n' || style().preserveNewline()) && text[i] != '\t')
606             break;
607     }
608     return i;
609 }
610
611 void RenderText::trimmedPrefWidths(float leadWidth,
612                                    float& beginMinW, bool& beginWS,
613                                    float& endMinW, bool& endWS,
614                                    bool& hasBreakableChar, bool& hasBreak,
615                                    float& beginMaxW, float& endMaxW,
616                                    float& minW, float& maxW, bool& stripFrontSpaces)
617 {
618     const RenderStyle& style = this->style();
619     bool collapseWhiteSpace = style.collapseWhiteSpace();
620     if (!collapseWhiteSpace)
621         stripFrontSpaces = false;
622
623     if (m_hasTab || preferredLogicalWidthsDirty())
624         computePreferredLogicalWidths(leadWidth);
625
626     beginWS = !stripFrontSpaces && m_hasBeginWS;
627     endWS = m_hasEndWS;
628
629     unsigned len = textLength();
630
631     if (!len || (stripFrontSpaces && text()->containsOnlyWhitespace())) {
632         beginMinW = 0;
633         endMinW = 0;
634         beginMaxW = 0;
635         endMaxW = 0;
636         minW = 0;
637         maxW = 0;
638         hasBreak = false;
639         return;
640     }
641
642     minW = m_minWidth;
643     maxW = m_maxWidth;
644
645     beginMinW = m_beginMinWidth;
646     endMinW = m_endMinWidth;
647
648     hasBreakableChar = m_hasBreakableChar;
649     hasBreak = m_hasBreak;
650
651     ASSERT(m_text);
652     StringImpl& text = *m_text.impl();
653     if (text[0] == space || (text[0] == newlineCharacter && !style.preserveNewline()) || text[0] == '\t') {
654         const FontCascade& font = style.fontCascade(); // FIXME: This ignores first-line.
655         if (stripFrontSpaces) {
656             float spaceWidth = font.width(RenderBlock::constructTextRun(&space, 1, style));
657             maxW -= spaceWidth;
658         } else
659             maxW += font.wordSpacing();
660     }
661
662     stripFrontSpaces = collapseWhiteSpace && m_hasEndWS;
663
664     if (!style.autoWrap() || minW > maxW)
665         minW = maxW;
666
667     // Compute our max widths by scanning the string for newlines.
668     if (hasBreak) {
669         const FontCascade& f = style.fontCascade(); // FIXME: This ignores first-line.
670         bool firstLine = true;
671         beginMaxW = maxW;
672         endMaxW = maxW;
673         for (unsigned i = 0; i < len; i++) {
674             unsigned linelen = 0;
675             while (i + linelen < len && text[i + linelen] != '\n')
676                 linelen++;
677
678             if (linelen) {
679                 endMaxW = widthFromCache(f, i, linelen, leadWidth + endMaxW, 0, 0, style);
680                 if (firstLine) {
681                     firstLine = false;
682                     leadWidth = 0;
683                     beginMaxW = endMaxW;
684                 }
685                 i += linelen;
686             } else if (firstLine) {
687                 beginMaxW = 0;
688                 firstLine = false;
689                 leadWidth = 0;
690             }
691
692             if (i == len - 1)
693                 // A <pre> run that ends with a newline, as in, e.g.,
694                 // <pre>Some text\n\n<span>More text</pre>
695                 endMaxW = 0;
696         }
697     }
698 }
699
700 static inline bool isSpaceAccordingToStyle(UChar c, const RenderStyle& style)
701 {
702     return c == ' ' || (c == noBreakSpace && style.nbspMode() == SPACE);
703 }
704
705 float RenderText::minLogicalWidth() const
706 {
707     if (preferredLogicalWidthsDirty())
708         const_cast<RenderText*>(this)->computePreferredLogicalWidths(0);
709         
710     return m_minWidth;
711 }
712
713 float RenderText::maxLogicalWidth() const
714 {
715     if (preferredLogicalWidthsDirty())
716         const_cast<RenderText*>(this)->computePreferredLogicalWidths(0);
717         
718     return m_maxWidth;
719 }
720
721 LineBreakIteratorMode mapLineBreakToIteratorMode(LineBreak lineBreak)
722 {
723     switch (lineBreak) {
724     case LineBreakAuto:
725     case LineBreakAfterWhiteSpace:
726         return LineBreakIteratorMode::Default;
727     case LineBreakLoose:
728         return LineBreakIteratorMode::Loose;
729     case LineBreakNormal:
730         return LineBreakIteratorMode::Normal;
731     case LineBreakStrict:
732         return LineBreakIteratorMode::Strict;
733     }
734     ASSERT_NOT_REACHED();
735     return LineBreakIteratorMode::Default;
736 }
737
738 void RenderText::computePreferredLogicalWidths(float leadWidth)
739 {
740     HashSet<const Font*> fallbackFonts;
741     GlyphOverflow glyphOverflow;
742     computePreferredLogicalWidths(leadWidth, fallbackFonts, glyphOverflow);
743     if (fallbackFonts.isEmpty() && !glyphOverflow.left && !glyphOverflow.right && !glyphOverflow.top && !glyphOverflow.bottom)
744         m_knownToHaveNoOverflowAndNoFallbackFonts = true;
745 }
746
747 static inline float hyphenWidth(RenderText& renderer, const FontCascade& font)
748 {
749     const RenderStyle& style = renderer.style();
750     auto textRun = RenderBlock::constructTextRun(style.hyphenString().string(), style);
751     return font.width(textRun);
752 }
753
754 static float maxWordFragmentWidth(RenderText& renderer, const RenderStyle& style, const FontCascade& font, StringView word, unsigned minimumPrefixLength, unsigned minimumSuffixLength, unsigned& suffixStart, HashSet<const Font*>& fallbackFonts, GlyphOverflow& glyphOverflow)
755 {
756     suffixStart = 0;
757     if (word.length() <= minimumSuffixLength)
758         return 0;
759
760     Vector<int, 8> hyphenLocations;
761     ASSERT(word.length() >= minimumSuffixLength);
762     unsigned hyphenLocation = word.length() - minimumSuffixLength;
763     while ((hyphenLocation = lastHyphenLocation(word, hyphenLocation, style.locale())) >= std::max(minimumPrefixLength, 1U))
764         hyphenLocations.append(hyphenLocation);
765
766     if (hyphenLocations.isEmpty())
767         return 0;
768
769     hyphenLocations.reverse();
770
771     // FIXME: Breaking the string at these places in the middle of words is completely broken with complex text.
772     float minimumFragmentWidthToConsider = font.pixelSize() * 5 / 4 + hyphenWidth(renderer, font);
773     float maxFragmentWidth = 0;
774     for (size_t k = 0; k < hyphenLocations.size(); ++k) {
775         int fragmentLength = hyphenLocations[k] - suffixStart;
776         StringBuilder fragmentWithHyphen;
777         fragmentWithHyphen.append(word.substring(suffixStart, fragmentLength));
778         fragmentWithHyphen.append(style.hyphenString());
779
780         TextRun run = RenderBlock::constructTextRun(fragmentWithHyphen.toString(), style);
781         run.setCharacterScanForCodePath(!renderer.canUseSimpleFontCodePath());
782         float fragmentWidth = font.width(run, &fallbackFonts, &glyphOverflow);
783
784         // Narrow prefixes are ignored. See tryHyphenating in RenderBlockLineLayout.cpp.
785         if (fragmentWidth <= minimumFragmentWidthToConsider)
786             continue;
787
788         suffixStart += fragmentLength;
789         maxFragmentWidth = std::max(maxFragmentWidth, fragmentWidth);
790     }
791
792     return maxFragmentWidth;
793 }
794
795 void RenderText::computePreferredLogicalWidths(float leadWidth, HashSet<const Font*>& fallbackFonts, GlyphOverflow& glyphOverflow)
796 {
797     ASSERT(m_hasTab || preferredLogicalWidthsDirty() || !m_knownToHaveNoOverflowAndNoFallbackFonts);
798
799     m_minWidth = 0;
800     m_beginMinWidth = 0;
801     m_endMinWidth = 0;
802     m_maxWidth = 0;
803
804     float currMaxWidth = 0;
805     m_hasBreakableChar = false;
806     m_hasBreak = false;
807     m_hasTab = false;
808     m_hasBeginWS = false;
809     m_hasEndWS = false;
810
811     const RenderStyle& style = this->style();
812     const FontCascade& font = style.fontCascade(); // FIXME: This ignores first-line.
813     float wordSpacing = font.wordSpacing();
814     unsigned len = textLength();
815     auto iteratorMode = mapLineBreakToIteratorMode(style.lineBreak());
816     LazyLineBreakIterator breakIterator(m_text, style.locale(), iteratorMode);
817     bool needsWordSpacing = false;
818     bool ignoringSpaces = false;
819     bool isSpace = false;
820     bool firstWord = true;
821     bool firstLine = true;
822     std::optional<unsigned> nextBreakable;
823     unsigned lastWordBoundary = 0;
824
825     WordTrailingSpace wordTrailingSpace(style);
826     // If automatic hyphenation is allowed, we keep track of the width of the widest word (or word
827     // fragment) encountered so far, and only try hyphenating words that are wider.
828     float maxWordWidth = std::numeric_limits<float>::max();
829     unsigned minimumPrefixLength = 0;
830     unsigned minimumSuffixLength = 0;
831     if (style.hyphens() == HyphensAuto && canHyphenate(style.locale())) {
832         maxWordWidth = 0;
833
834         // Map 'hyphenate-limit-{before,after}: auto;' to 2.
835         auto before = style.hyphenationLimitBefore();
836         minimumPrefixLength = before < 0 ? 2 : before;
837
838         auto after = style.hyphenationLimitAfter();
839         minimumSuffixLength = after < 0 ? 2 : after;
840     }
841
842     std::optional<int> firstGlyphLeftOverflow;
843
844     bool breakNBSP = style.autoWrap() && style.nbspMode() == SPACE;
845     
846     // Note the deliberate omission of word-wrap and overflow-wrap from this breakAll check. Those
847     // do not affect minimum preferred sizes. Note that break-word is a non-standard value for
848     // word-break, but we support it as though it means break-all.
849     bool breakAll = (style.wordBreak() == BreakAllWordBreak || style.wordBreak() == BreakWordBreak) && style.autoWrap();
850     bool keepAllWords = style.wordBreak() == KeepAllWordBreak;
851     bool canUseLineBreakShortcut = iteratorMode == LineBreakIteratorMode::Default;
852
853     for (unsigned i = 0; i < len; i++) {
854         UChar c = uncheckedCharacterAt(i);
855
856         bool previousCharacterIsSpace = isSpace;
857
858         bool isNewline = false;
859         if (c == '\n') {
860             if (style.preserveNewline()) {
861                 m_hasBreak = true;
862                 isNewline = true;
863                 isSpace = false;
864             } else
865                 isSpace = true;
866         } else if (c == '\t') {
867             if (!style.collapseWhiteSpace()) {
868                 m_hasTab = true;
869                 isSpace = false;
870             } else
871                 isSpace = true;
872         } else
873             isSpace = c == ' ';
874
875         if ((isSpace || isNewline) && !i)
876             m_hasBeginWS = true;
877         if ((isSpace || isNewline) && i == len - 1)
878             m_hasEndWS = true;
879
880         ignoringSpaces |= style.collapseWhiteSpace() && previousCharacterIsSpace && isSpace;
881         ignoringSpaces &= isSpace;
882
883         // Ignore spaces and soft hyphens
884         if (ignoringSpaces) {
885             ASSERT(lastWordBoundary == i);
886             lastWordBoundary++;
887             continue;
888         } else if (c == softHyphen && style.hyphens() != HyphensNone) {
889             ASSERT(i >= lastWordBoundary);
890             currMaxWidth += widthFromCache(font, lastWordBoundary, i - lastWordBoundary, leadWidth + currMaxWidth, &fallbackFonts, &glyphOverflow, style);
891             if (!firstGlyphLeftOverflow)
892                 firstGlyphLeftOverflow = glyphOverflow.left;
893             lastWordBoundary = i + 1;
894             continue;
895         }
896
897         bool hasBreak = breakAll || isBreakable(breakIterator, i, nextBreakable, breakNBSP, canUseLineBreakShortcut, keepAllWords);
898         bool betweenWords = true;
899         unsigned j = i;
900         while (c != '\n' && !isSpaceAccordingToStyle(c, style) && c != '\t' && (c != softHyphen || style.hyphens() == HyphensNone)) {
901             j++;
902             if (j == len)
903                 break;
904             c = uncheckedCharacterAt(j);
905             if (isBreakable(breakIterator, j, nextBreakable, breakNBSP, canUseLineBreakShortcut, keepAllWords) && characterAt(j - 1) != softHyphen)
906                 break;
907             if (breakAll) {
908                 betweenWords = false;
909                 break;
910             }
911         }
912
913         unsigned wordLen = j - i;
914         if (wordLen) {
915             float currMinWidth = 0;
916             bool isSpace = (j < len) && isSpaceAccordingToStyle(c, style);
917             float w;
918             std::optional<float> wordTrailingSpaceWidth;
919             if (isSpace)
920                 wordTrailingSpaceWidth = wordTrailingSpace.width(fallbackFonts);
921             if (wordTrailingSpaceWidth)
922                 w = widthFromCache(font, i, wordLen + 1, leadWidth + currMaxWidth, &fallbackFonts, &glyphOverflow, style) - wordTrailingSpaceWidth.value();
923             else {
924                 w = widthFromCache(font, i, wordLen, leadWidth + currMaxWidth, &fallbackFonts, &glyphOverflow, style);
925                 if (c == softHyphen && style.hyphens() != HyphensNone)
926                     currMinWidth = hyphenWidth(*this, font);
927             }
928
929             if (w > maxWordWidth) {
930                 unsigned suffixStart;
931                 float maxFragmentWidth = maxWordFragmentWidth(*this, style, font, StringView(m_text).substring(i, wordLen), minimumPrefixLength, minimumSuffixLength, suffixStart, fallbackFonts, glyphOverflow);
932
933                 if (suffixStart) {
934                     float suffixWidth;
935                     std::optional<float> wordTrailingSpaceWidth;
936                     if (isSpace)
937                         wordTrailingSpaceWidth = wordTrailingSpace.width(fallbackFonts);
938                     if (wordTrailingSpaceWidth)
939                         suffixWidth = widthFromCache(font, i + suffixStart, wordLen - suffixStart + 1, leadWidth + currMaxWidth, 0, 0, style) - wordTrailingSpaceWidth.value();
940                     else
941                         suffixWidth = widthFromCache(font, i + suffixStart, wordLen - suffixStart, leadWidth + currMaxWidth, 0, 0, style);
942
943                     maxFragmentWidth = std::max(maxFragmentWidth, suffixWidth);
944
945                     currMinWidth += maxFragmentWidth - w;
946                     maxWordWidth = std::max(maxWordWidth, maxFragmentWidth);
947                 } else
948                     maxWordWidth = w;
949             }
950
951             if (!firstGlyphLeftOverflow)
952                 firstGlyphLeftOverflow = glyphOverflow.left;
953             currMinWidth += w;
954             if (betweenWords) {
955                 if (lastWordBoundary == i)
956                     currMaxWidth += w;
957                 else {
958                     ASSERT(j >= lastWordBoundary);
959                     currMaxWidth += widthFromCache(font, lastWordBoundary, j - lastWordBoundary, leadWidth + currMaxWidth, &fallbackFonts, &glyphOverflow, style);
960                 }
961                 lastWordBoundary = j;
962             }
963
964             bool isCollapsibleWhiteSpace = (j < len) && style.isCollapsibleWhiteSpace(c);
965             if (j < len && style.autoWrap())
966                 m_hasBreakableChar = true;
967
968             // Add in wordSpacing to our currMaxWidth, but not if this is the last word on a line or the
969             // last word in the run.
970             if ((isSpace || isCollapsibleWhiteSpace) && !containsOnlyWhitespace(j, len-j))
971                 currMaxWidth += wordSpacing;
972
973             if (firstWord) {
974                 firstWord = false;
975                 // If the first character in the run is breakable, then we consider ourselves to have a beginning
976                 // minimum width of 0, since a break could occur right before our run starts, preventing us from ever
977                 // being appended to a previous text run when considering the total minimum width of the containing block.
978                 if (hasBreak)
979                     m_hasBreakableChar = true;
980                 m_beginMinWidth = hasBreak ? 0 : currMinWidth;
981             }
982             m_endMinWidth = currMinWidth;
983
984             m_minWidth = std::max(currMinWidth, m_minWidth);
985
986             i += wordLen - 1;
987         } else {
988             // Nowrap can never be broken, so don't bother setting the
989             // breakable character boolean. Pre can only be broken if we encounter a newline.
990             if (style.autoWrap() || isNewline)
991                 m_hasBreakableChar = true;
992
993             if (isNewline) { // Only set if preserveNewline was true and we saw a newline.
994                 if (firstLine) {
995                     firstLine = false;
996                     leadWidth = 0;
997                     if (!style.autoWrap())
998                         m_beginMinWidth = currMaxWidth;
999                 }
1000
1001                 if (currMaxWidth > m_maxWidth)
1002                     m_maxWidth = currMaxWidth;
1003                 currMaxWidth = 0;
1004             } else {
1005                 TextRun run = RenderBlock::constructTextRun(*this, i, 1, style);
1006                 run.setTabSize(!style.collapseWhiteSpace(), style.tabSize());
1007                 run.setXPos(leadWidth + currMaxWidth);
1008
1009                 currMaxWidth += font.width(run, &fallbackFonts);
1010                 glyphOverflow.right = 0;
1011                 needsWordSpacing = isSpace && !previousCharacterIsSpace && i == len - 1;
1012             }
1013             ASSERT(lastWordBoundary == i);
1014             lastWordBoundary++;
1015         }
1016     }
1017
1018     glyphOverflow.left = firstGlyphLeftOverflow.value_or(glyphOverflow.left);
1019
1020     if ((needsWordSpacing && len > 1) || (ignoringSpaces && !firstWord))
1021         currMaxWidth += wordSpacing;
1022
1023     m_maxWidth = std::max(currMaxWidth, m_maxWidth);
1024
1025     if (!style.autoWrap())
1026         m_minWidth = m_maxWidth;
1027
1028     if (style.whiteSpace() == PRE) {
1029         if (firstLine)
1030             m_beginMinWidth = m_maxWidth;
1031         m_endMinWidth = currMaxWidth;
1032     }
1033
1034     setPreferredLogicalWidthsDirty(false);
1035 }
1036
1037 bool RenderText::isAllCollapsibleWhitespace() const
1038 {
1039     const RenderStyle& style = this->style();
1040     unsigned length = textLength();
1041     if (is8Bit()) {
1042         for (unsigned i = 0; i < length; ++i) {
1043             if (!style.isCollapsibleWhiteSpace(characters8()[i]))
1044                 return false;
1045         }
1046         return true;
1047     }
1048     for (unsigned i = 0; i < length; ++i) {
1049         if (!style.isCollapsibleWhiteSpace(characters16()[i]))
1050             return false;
1051     }
1052     return true;
1053 }
1054     
1055 bool RenderText::containsOnlyWhitespace(unsigned from, unsigned len) const
1056 {
1057     ASSERT(m_text);
1058     StringImpl& text = *m_text.impl();
1059     unsigned currPos;
1060     for (currPos = from;
1061          currPos < from + len && (text[currPos] == '\n' || text[currPos] == ' ' || text[currPos] == '\t');
1062          currPos++) { }
1063     return currPos >= (from + len);
1064 }
1065
1066 Vector<std::pair<unsigned, unsigned>> RenderText::draggedContentRangesBetweenOffsets(unsigned startOffset, unsigned endOffset) const
1067 {
1068     if (!textNode())
1069         return { };
1070
1071     auto markers = document().markers().markersFor(textNode(), DocumentMarker::DraggedContent);
1072     if (markers.isEmpty())
1073         return { };
1074
1075     Vector<std::pair<unsigned, unsigned>> draggedContentRanges;
1076     for (auto* marker : markers) {
1077         unsigned markerStart = std::max(marker->startOffset(), startOffset);
1078         unsigned markerEnd = std::min(marker->endOffset(), endOffset);
1079         if (markerStart >= markerEnd || markerStart > endOffset || markerEnd < startOffset)
1080             continue;
1081
1082         std::pair<unsigned, unsigned> draggedContentRange;
1083         draggedContentRange.first = markerStart;
1084         draggedContentRange.second = markerEnd;
1085         draggedContentRanges.append(draggedContentRange);
1086     }
1087     return draggedContentRanges;
1088 }
1089
1090 IntPoint RenderText::firstRunLocation() const
1091 {
1092     if (auto* layout = simpleLineLayout())
1093         return SimpleLineLayout::computeFirstRunLocation(*this, *layout);
1094
1095     return m_lineBoxes.firstRunLocation();
1096 }
1097
1098 void RenderText::setSelectionState(SelectionState state)
1099 {
1100     if (state != SelectionNone)
1101         ensureLineBoxes();
1102
1103     RenderObject::setSelectionState(state);
1104
1105     if (canUpdateSelectionOnRootLineBoxes())
1106         m_lineBoxes.setSelectionState(*this, state);
1107
1108     // The containing block can be null in case of an orphaned tree.
1109     RenderBlock* containingBlock = this->containingBlock();
1110     if (containingBlock && !containingBlock->isRenderView())
1111         containingBlock->setSelectionState(state);
1112 }
1113
1114 void RenderText::setTextWithOffset(const String& text, unsigned offset, unsigned len, bool force)
1115 {
1116     if (!force && m_text == text)
1117         return;
1118
1119     int delta = text.length() - textLength();
1120     unsigned end = len ? offset + len - 1 : offset;
1121
1122     m_linesDirty = simpleLineLayout() || m_lineBoxes.dirtyRange(*this, offset, end, delta);
1123
1124     setText(text, force || m_linesDirty);
1125 }
1126
1127 static inline bool isInlineFlowOrEmptyText(const RenderObject& renderer)
1128 {
1129     if (is<RenderInline>(renderer))
1130         return true;
1131     if (!is<RenderText>(renderer))
1132         return false;
1133     StringImpl* text = downcast<RenderText>(renderer).text();
1134     if (!text)
1135         return true;
1136     return !text->length();
1137 }
1138
1139 UChar RenderText::previousCharacter() const
1140 {
1141     // find previous text renderer if one exists
1142     const RenderObject* previousText = this;
1143     while ((previousText = previousText->previousInPreOrder()))
1144         if (!isInlineFlowOrEmptyText(*previousText))
1145             break;
1146     UChar prev = ' ';
1147     if (is<RenderText>(previousText)) {
1148         if (StringImpl* previousString = downcast<RenderText>(*previousText).text())
1149             prev = (*previousString)[previousString->length() - 1];
1150     }
1151     return prev;
1152 }
1153
1154 LayoutUnit RenderText::topOfFirstText() const
1155 {
1156     return firstTextBox()->root().lineTop();
1157 }
1158
1159 void applyTextTransform(const RenderStyle& style, String& text, UChar previousCharacter)
1160 {
1161     switch (style.textTransform()) {
1162     case TTNONE:
1163         break;
1164     case CAPITALIZE:
1165         makeCapitalized(&text, previousCharacter);
1166         break;
1167     case UPPERCASE:
1168         text = text.convertToUppercaseWithLocale(style.locale());
1169         break;
1170     case LOWERCASE:
1171         text = text.convertToLowercaseWithLocale(style.locale());
1172         break;
1173     }
1174 }
1175
1176 void RenderText::setRenderedText(const String& text)
1177 {
1178     ASSERT(!text.isNull());
1179
1180     String originalText = this->originalText();
1181
1182     m_text = text;
1183
1184     if (m_useBackslashAsYenSymbol)
1185         m_text.replace('\\', yenSign);
1186
1187     ASSERT(m_text);
1188
1189     applyTextTransform(style(), m_text, previousCharacter());
1190
1191     switch (style().textSecurity()) {
1192     case TSNONE:
1193         break;
1194 #if !PLATFORM(IOS)
1195     // We use the same characters here as for list markers.
1196     // See the listMarkerText function in RenderListMarker.cpp.
1197     case TSCIRCLE:
1198         secureText(whiteBullet);
1199         break;
1200     case TSDISC:
1201         secureText(bullet);
1202         break;
1203     case TSSQUARE:
1204         secureText(blackSquare);
1205         break;
1206 #else
1207     // FIXME: Why this quirk on iOS?
1208     case TSCIRCLE:
1209     case TSDISC:
1210     case TSSQUARE:
1211         secureText(blackCircle);
1212         break;
1213 #endif
1214     }
1215
1216     ASSERT(!m_text.isNull());
1217
1218     m_isAllASCII = m_text.containsOnlyASCII();
1219     m_canUseSimpleFontCodePath = computeCanUseSimpleFontCodePath();
1220     m_canUseSimplifiedTextMeasuring = computeCanUseSimplifiedTextMeasuring();
1221     
1222     if (m_text != originalText) {
1223         originalTextMap().set(this, originalText);
1224         m_originalTextDiffersFromRendered = true;
1225     } else if (m_originalTextDiffersFromRendered) {
1226         originalTextMap().remove(this);
1227         m_originalTextDiffersFromRendered = false;
1228     }
1229 }
1230
1231 void RenderText::secureText(UChar maskingCharacter)
1232 {
1233     // This hides the text by replacing all the characters with the masking character.
1234     // Offsets within the hidden text have to match offsets within the original text
1235     // to handle things like carets and selection, so this won't work right if any
1236     // of the characters are surrogate pairs or combining marks. Thus, this function
1237     // does not attempt to handle either of those.
1238
1239     unsigned length = textLength();
1240     if (!length)
1241         return;
1242
1243     UChar characterToReveal = 0;
1244     unsigned revealedCharactersOffset = 0;
1245
1246     if (SecureTextTimer* timer = secureTextTimers().get(this)) {
1247         // We take the offset out of the timer to make this one-shot. We count on this being called only once.
1248         // If it's called a second time we assume the text is different and a character should not be revealed.
1249         revealedCharactersOffset = timer->takeOffsetAfterLastTypedCharacter();
1250         if (revealedCharactersOffset && revealedCharactersOffset <= length)
1251             characterToReveal = m_text[--revealedCharactersOffset];
1252     }
1253
1254     UChar* characters;
1255     m_text = String::createUninitialized(length, characters);
1256
1257     for (unsigned i = 0; i < length; ++i)
1258         characters[i] = maskingCharacter;
1259     if (characterToReveal)
1260         characters[revealedCharactersOffset] = characterToReveal;
1261 }
1262
1263 bool RenderText::computeCanUseSimplifiedTextMeasuring() const
1264 {
1265     if (!m_canUseSimpleFontCodePath)
1266         return false;
1267     
1268     auto& font = style().fontCascade();
1269     if (font.wordSpacing() || font.letterSpacing())
1270         return false;
1271
1272     // Additional check on the font codepath.
1273     TextRun run(m_text);
1274     run.setCharacterScanForCodePath(false);
1275     if (font.codePath(run) != FontCascade::Simple)
1276         return false;
1277
1278     auto whitespaceIsCollapsed = style().collapseWhiteSpace();
1279     for (unsigned i = 0; i < m_text.length(); ++i) {
1280         if ((!whitespaceIsCollapsed && m_text[i] == '\t') || m_text[i] == noBreakSpace || m_text[i] >= HiraganaLetterSmallA)
1281             return false;
1282     }
1283     return true;
1284 }
1285
1286 void RenderText::setText(const String& text, bool force)
1287 {
1288     ASSERT(!text.isNull());
1289
1290     if (!force && text == originalText())
1291         return;
1292
1293     m_text = text;
1294     if (m_originalTextDiffersFromRendered) {
1295         originalTextMap().remove(this);
1296         m_originalTextDiffersFromRendered = false;
1297     }
1298
1299     setRenderedText(text);
1300
1301     setNeedsLayoutAndPrefWidthsRecalc();
1302     m_knownToHaveNoOverflowAndNoFallbackFonts = false;
1303
1304     if (is<RenderBlockFlow>(*parent()))
1305         downcast<RenderBlockFlow>(*parent()).invalidateLineLayoutPath();
1306     
1307     if (AXObjectCache* cache = document().existingAXObjectCache())
1308         cache->deferTextChangedIfNeeded(textNode());
1309 }
1310
1311 String RenderText::textWithoutConvertingBackslashToYenSymbol() const
1312 {
1313     if (!m_useBackslashAsYenSymbol || style().textSecurity() != TSNONE)
1314         return text();
1315
1316     String text = originalText();
1317     applyTextTransform(style(), text, previousCharacter());
1318     return text;
1319 }
1320
1321 void RenderText::dirtyLineBoxes(bool fullLayout)
1322 {
1323     if (fullLayout)
1324         m_lineBoxes.deleteAll();
1325     else if (!m_linesDirty)
1326         m_lineBoxes.dirtyAll();
1327     m_linesDirty = false;
1328 }
1329
1330 std::unique_ptr<InlineTextBox> RenderText::createTextBox()
1331 {
1332     return std::make_unique<InlineTextBox>(*this);
1333 }
1334
1335 void RenderText::positionLineBox(InlineTextBox& textBox)
1336 {
1337     if (!textBox.len())
1338         return;
1339     m_containsReversedText |= !textBox.isLeftToRightDirection();
1340 }
1341
1342 void RenderText::ensureLineBoxes()
1343 {
1344     if (!is<RenderBlockFlow>(*parent()))
1345         return;
1346     downcast<RenderBlockFlow>(*parent()).ensureLineBoxes();
1347 }
1348
1349 const SimpleLineLayout::Layout* RenderText::simpleLineLayout() const
1350 {
1351     if (!is<RenderBlockFlow>(*parent()))
1352         return nullptr;
1353     return downcast<RenderBlockFlow>(*parent()).simpleLineLayout();
1354 }
1355
1356 float RenderText::width(unsigned from, unsigned len, float xPos, bool firstLine, HashSet<const Font*>* fallbackFonts, GlyphOverflow* glyphOverflow) const
1357 {
1358     if (from >= textLength())
1359         return 0;
1360
1361     if (from + len > textLength())
1362         len = textLength() - from;
1363
1364     const RenderStyle& lineStyle = firstLine ? firstLineStyle() : style();
1365     return width(from, len, lineStyle.fontCascade(), xPos, fallbackFonts, glyphOverflow);
1366 }
1367
1368 float RenderText::width(unsigned from, unsigned len, const FontCascade& f, float xPos, HashSet<const Font*>* fallbackFonts, GlyphOverflow* glyphOverflow) const
1369 {
1370     ASSERT(from + len <= textLength());
1371     if (!textLength())
1372         return 0;
1373
1374     const RenderStyle& style = this->style();
1375     float w;
1376     if (&f == &style.fontCascade()) {
1377         if (!style.preserveNewline() && !from && len == textLength() && (!glyphOverflow || !glyphOverflow->computeBounds)) {
1378             if (fallbackFonts) {
1379                 ASSERT(glyphOverflow);
1380                 if (preferredLogicalWidthsDirty() || !m_knownToHaveNoOverflowAndNoFallbackFonts) {
1381                     const_cast<RenderText*>(this)->computePreferredLogicalWidths(0, *fallbackFonts, *glyphOverflow);
1382                     if (fallbackFonts->isEmpty() && !glyphOverflow->left && !glyphOverflow->right && !glyphOverflow->top && !glyphOverflow->bottom)
1383                         m_knownToHaveNoOverflowAndNoFallbackFonts = true;
1384                 }
1385                 w = m_maxWidth;
1386             } else
1387                 w = maxLogicalWidth();
1388         } else
1389             w = widthFromCache(f, from, len, xPos, fallbackFonts, glyphOverflow, style);
1390     } else {
1391         TextRun run = RenderBlock::constructTextRun(*this, from, len, style);
1392         run.setCharacterScanForCodePath(!canUseSimpleFontCodePath());
1393         run.setTabSize(!style.collapseWhiteSpace(), style.tabSize());
1394         run.setXPos(xPos);
1395
1396         w = f.width(run, fallbackFonts, glyphOverflow);
1397     }
1398
1399     return w;
1400 }
1401
1402 IntRect RenderText::linesBoundingBox() const
1403 {
1404     if (auto* layout = simpleLineLayout())
1405         return SimpleLineLayout::computeBoundingBox(*this, *layout);
1406
1407     return m_lineBoxes.boundingBox(*this);
1408 }
1409
1410 LayoutRect RenderText::linesVisualOverflowBoundingBox() const
1411 {
1412     ASSERT(!simpleLineLayout());
1413     return m_lineBoxes.visualOverflowBoundingBox(*this);
1414 }
1415
1416 LayoutRect RenderText::clippedOverflowRectForRepaint(const RenderLayerModelObject* repaintContainer) const
1417 {
1418     RenderObject* rendererToRepaint = containingBlock();
1419
1420     // Do not cross self-painting layer boundaries.
1421     RenderObject& enclosingLayerRenderer = enclosingLayer()->renderer();
1422     if (&enclosingLayerRenderer != rendererToRepaint && !rendererToRepaint->isDescendantOf(&enclosingLayerRenderer))
1423         rendererToRepaint = &enclosingLayerRenderer;
1424
1425     // The renderer we chose to repaint may be an ancestor of repaintContainer, but we need to do a repaintContainer-relative repaint.
1426     if (repaintContainer && repaintContainer != rendererToRepaint && !rendererToRepaint->isDescendantOf(repaintContainer))
1427         return repaintContainer->clippedOverflowRectForRepaint(repaintContainer);
1428
1429     return rendererToRepaint->clippedOverflowRectForRepaint(repaintContainer);
1430 }
1431
1432 LayoutRect RenderText::collectSelectionRectsForLineBoxes(const RenderLayerModelObject* repaintContainer, bool clipToVisibleContent, Vector<LayoutRect>* rects)
1433 {
1434     ASSERT(!needsLayout());
1435     ASSERT(!simpleLineLayout());
1436
1437     if (selectionState() == SelectionNone)
1438         return LayoutRect();
1439     if (!containingBlock())
1440         return LayoutRect();
1441
1442     // Now calculate startPos and endPos for painting selection.
1443     // We include a selection while endPos > 0
1444     unsigned startPos, endPos;
1445     if (selectionState() == SelectionInside) {
1446         // We are fully selected.
1447         startPos = 0;
1448         endPos = textLength();
1449     } else {
1450         view().getSelectionStartEnd(startPos, endPos);
1451         if (selectionState() == SelectionStart)
1452             endPos = textLength();
1453         else if (selectionState() == SelectionEnd)
1454             startPos = 0;
1455     }
1456
1457     if (startPos == endPos)
1458         return IntRect();
1459
1460     LayoutRect resultRect;
1461     if (!rects)
1462         resultRect = m_lineBoxes.selectionRectForRange(startPos, endPos);
1463     else {
1464         m_lineBoxes.collectSelectionRectsForRange(startPos, endPos, *rects);
1465         for (auto& rect : *rects) {
1466             resultRect.unite(rect);
1467             rect = localToContainerQuad(FloatRect(rect), repaintContainer).enclosingBoundingBox();
1468         }
1469     }
1470
1471     if (clipToVisibleContent)
1472         return computeRectForRepaint(resultRect, repaintContainer);
1473     return localToContainerQuad(FloatRect(resultRect), repaintContainer).enclosingBoundingBox();
1474 }
1475
1476 LayoutRect RenderText::collectSelectionRectsForLineBoxes(const RenderLayerModelObject* repaintContainer, bool clipToVisibleContent, Vector<LayoutRect>& rects)
1477 {
1478     return collectSelectionRectsForLineBoxes(repaintContainer, clipToVisibleContent, &rects);
1479 }
1480
1481 LayoutRect RenderText::selectionRectForRepaint(const RenderLayerModelObject* repaintContainer, bool clipToVisibleContent)
1482 {
1483     return collectSelectionRectsForLineBoxes(repaintContainer, clipToVisibleContent, nullptr);
1484 }
1485
1486 int RenderText::caretMinOffset() const
1487 {
1488     if (auto* layout = simpleLineLayout())
1489         return SimpleLineLayout::findCaretMinimumOffset(*this, *layout);
1490     return m_lineBoxes.caretMinOffset();
1491 }
1492
1493 int RenderText::caretMaxOffset() const
1494 {
1495     if (auto* layout = simpleLineLayout())
1496         return SimpleLineLayout::findCaretMaximumOffset(*this, *layout);
1497     return m_lineBoxes.caretMaxOffset(*this);
1498 }
1499
1500 unsigned RenderText::countRenderedCharacterOffsetsUntil(unsigned offset) const
1501 {
1502     ASSERT(!simpleLineLayout());
1503     return m_lineBoxes.countCharacterOffsetsUntil(offset);
1504 }
1505
1506 bool RenderText::containsRenderedCharacterOffset(unsigned offset) const
1507 {
1508     ASSERT(!simpleLineLayout());
1509     return m_lineBoxes.containsOffset(*this, offset, RenderTextLineBoxes::CharacterOffset);
1510 }
1511
1512 bool RenderText::containsCaretOffset(unsigned offset) const
1513 {
1514     if (auto* layout = simpleLineLayout())
1515         return SimpleLineLayout::containsCaretOffset(*this, *layout, offset);
1516     return m_lineBoxes.containsOffset(*this, offset, RenderTextLineBoxes::CaretOffset);
1517 }
1518
1519 bool RenderText::hasRenderedText() const
1520 {
1521     if (auto* layout = simpleLineLayout())
1522         return SimpleLineLayout::isTextRendered(*this, *layout);
1523     return m_lineBoxes.hasRenderedText();
1524 }
1525
1526 int RenderText::previousOffset(int current) const
1527 {
1528     if (isAllASCII() || m_text.is8Bit())
1529         return current - 1;
1530
1531     StringImpl* textImpl = m_text.impl();
1532     CachedTextBreakIterator iterator(StringView(textImpl->characters16(), textImpl->length()), TextBreakIterator::Mode::Caret, nullAtom());
1533     auto result = iterator.preceding(current).value_or(current - 1);
1534     return result;
1535 }
1536
1537 #if PLATFORM(COCOA) || PLATFORM(GTK)
1538
1539 const UChar hangulChoseongStart = 0x1100;
1540 const UChar hangulChoseongEnd = 0x115F;
1541 const UChar hangulJungseongStart = 0x1160;
1542 const UChar hangulJungseongEnd = 0x11A2;
1543 const UChar hangulJongseongStart = 0x11A8;
1544 const UChar hangulJongseongEnd = 0x11F9;
1545 const UChar hangulSyllableStart = 0xAC00;
1546 const UChar hangulSyllableEnd = 0xD7AF;
1547 const UChar hangulJongseongCount = 28;
1548
1549 enum class HangulState { L, V, T, LV, LVT, Break };
1550
1551 static inline bool isHangulLVT(UChar character)
1552 {
1553     return (character - hangulSyllableStart) % hangulJongseongCount;
1554 }
1555
1556 static inline bool isMark(UChar32 character)
1557 {
1558     return U_GET_GC_MASK(character) & U_GC_M_MASK;
1559 }
1560
1561 static inline bool isRegionalIndicator(UChar32 character)
1562 {
1563     // National flag emoji each consists of a pair of regional indicator symbols.
1564     return 0x1F1E6 <= character && character <= 0x1F1FF;
1565 }
1566
1567 static inline bool isInArmenianToLimbuRange(UChar32 character)
1568 {
1569     return character >= 0x0530 && character < 0x1950;
1570 }
1571
1572 #endif
1573
1574 int RenderText::previousOffsetForBackwardDeletion(int current) const
1575 {
1576     ASSERT(!m_text.isNull());
1577     StringImpl& text = *m_text.impl();
1578
1579     // FIXME: Unclear why this has so much handrolled code rather than using UBreakIterator.
1580     // Also unclear why this is so different from advanceByCombiningCharacterSequence.
1581
1582     // FIXME: Seems like this fancier case could be used on all platforms now, no
1583     // need for the #else case below.
1584 #if PLATFORM(COCOA) || PLATFORM(GTK)
1585     bool sawRegionalIndicator = false;
1586     bool sawEmojiGroupCandidate = false;
1587     bool sawEmojiFitzpatrickModifier = false;
1588     
1589     while (current > 0) {
1590         UChar32 character;
1591         U16_PREV(text, 0, current, character);
1592
1593         if (sawEmojiGroupCandidate) {
1594             sawEmojiGroupCandidate = false;
1595             if (character == zeroWidthJoiner)
1596                 continue;
1597             // We could have two emoji group candidates without a joiner in between.
1598             // Those should not be treated as a group.
1599             U16_FWD_1_UNSAFE(text, current);
1600             break;
1601         }
1602
1603         if (sawEmojiFitzpatrickModifier) {
1604             if (isEmojiFitzpatrickModifier(character)) {
1605                 // Don't treat two emoji modifiers in a row as a group.
1606                 U16_FWD_1_UNSAFE(text, current);
1607                 break;
1608             }
1609             if (!isVariationSelector(character))
1610                 break;
1611         }
1612
1613         if (sawRegionalIndicator) {
1614             // We don't check if the pair of regional indicator symbols before current position can actually be combined
1615             // into a flag, and just delete it. This may not agree with how the pair is rendered in edge cases,
1616             // but is good enough in practice.
1617             if (isRegionalIndicator(character))
1618                 break;
1619             // Don't delete a preceding character that isn't a regional indicator symbol.
1620             U16_FWD_1_UNSAFE(text, current);
1621         }
1622
1623         // We don't combine characters in Armenian ... Limbu range for backward deletion.
1624         if (isInArmenianToLimbuRange(character))
1625             break;
1626
1627         if (isRegionalIndicator(character)) {
1628             sawRegionalIndicator = true;
1629             continue;
1630         }
1631         
1632         if (isEmojiFitzpatrickModifier(character)) {
1633             sawEmojiFitzpatrickModifier = true;
1634             continue;
1635         }
1636
1637         if (isEmojiGroupCandidate(character)) {
1638             sawEmojiGroupCandidate = true;
1639             continue;
1640         }
1641
1642         // FIXME: Why are FF9E and FF9F special cased here?
1643         if (!isMark(character) && character != 0xFF9E && character != 0xFF9F)
1644             break;
1645     }
1646
1647     if (current <= 0)
1648         return current;
1649
1650     // Hangul
1651     UChar character = text[current];
1652     if ((character >= hangulChoseongStart && character <= hangulJongseongEnd) || (character >= hangulSyllableStart && character <= hangulSyllableEnd)) {
1653         HangulState state;
1654
1655         if (character < hangulJungseongStart)
1656             state = HangulState::L;
1657         else if (character < hangulJongseongStart)
1658             state = HangulState::V;
1659         else if (character < hangulSyllableStart)
1660             state = HangulState::T;
1661         else
1662             state = isHangulLVT(character) ? HangulState::LVT : HangulState::LV;
1663
1664         while (current > 0 && (character = text[current - 1]) >= hangulChoseongStart && character <= hangulSyllableEnd && (character <= hangulJongseongEnd || character >= hangulSyllableStart)) {
1665             switch (state) {
1666             case HangulState::V:
1667                 if (character <= hangulChoseongEnd)
1668                     state = HangulState::L;
1669                 else if (character >= hangulSyllableStart && character <= hangulSyllableEnd && !isHangulLVT(character))
1670                     state = HangulState::LV;
1671                 else if (character > hangulJungseongEnd)
1672                     state = HangulState::Break;
1673                 break;
1674             case HangulState::T:
1675                 if (character >= hangulJungseongStart && character <= hangulJungseongEnd)
1676                     state = HangulState::V;
1677                 else if (character >= hangulSyllableStart && character <= hangulSyllableEnd)
1678                     state = isHangulLVT(character) ? HangulState::LVT : HangulState::LV;
1679                 else if (character < hangulJungseongStart)
1680                     state = HangulState::Break;
1681                 break;
1682             default:
1683                 state = (character < hangulJungseongStart) ? HangulState::L : HangulState::Break;
1684                 break;
1685             }
1686             if (state == HangulState::Break)
1687                 break;
1688             --current;
1689         }
1690     }
1691
1692     return current;
1693 #else
1694     U16_BACK_1(text, 0, current);
1695     return current;
1696 #endif
1697 }
1698
1699 int RenderText::nextOffset(int current) const
1700 {
1701     if (isAllASCII() || m_text.is8Bit())
1702         return current + 1;
1703
1704     StringImpl* textImpl = m_text.impl();
1705     CachedTextBreakIterator iterator(StringView(textImpl->characters16(), textImpl->length()), TextBreakIterator::Mode::Caret, nullAtom());
1706     auto result = iterator.following(current).value_or(current + 1);
1707     return result;
1708 }
1709
1710 bool RenderText::computeCanUseSimpleFontCodePath() const
1711 {
1712     if (isAllASCII() || m_text.is8Bit())
1713         return true;
1714     return FontCascade::characterRangeCodePath(characters16(), length()) == FontCascade::Simple;
1715 }
1716
1717 void RenderText::momentarilyRevealLastTypedCharacter(unsigned offsetAfterLastTypedCharacter)
1718 {
1719     if (style().textSecurity() == TSNONE)
1720         return;
1721     auto& secureTextTimer = secureTextTimers().add(this, nullptr).iterator->value;
1722     if (!secureTextTimer)
1723         secureTextTimer = std::make_unique<SecureTextTimer>(*this);
1724     secureTextTimer->restart(offsetAfterLastTypedCharacter);
1725 }
1726
1727 StringView RenderText::stringView(unsigned start, std::optional<unsigned> stop) const
1728 {
1729     unsigned destination = stop.value_or(textLength());
1730     ASSERT(start <= length());
1731     ASSERT(destination <= length());
1732     ASSERT(start <= destination);
1733     if (is8Bit())
1734         return StringView(characters8() + start, destination - start);
1735     return StringView(characters16() + start, destination - start);
1736 }
1737
1738 } // namespace WebCore