76185b3c9382484c600449c823f3fcb29a25b1f2
[WebKit-https.git] / Source / WebCore / rendering / RenderTextLineBoxes.cpp
1 /*
2  * Copyright (C) 2013 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "RenderTextLineBoxes.h"
28
29 #include "InlineTextBox.h"
30 #include "RenderStyle.h"
31
32 namespace WebCore {
33
34 RenderTextLineBoxes::RenderTextLineBoxes()
35     : m_first(nullptr)
36     , m_last(nullptr)
37 {
38 }
39
40 InlineTextBox* RenderTextLineBoxes::createAndAppendLineBox(RenderText& renderText)
41 {
42     auto textBox = renderText.createTextBox();
43     if (!m_first) {
44         m_first = textBox;
45         m_last = textBox;
46     } else {
47         m_last->setNextTextBox(textBox);
48         textBox->setPreviousTextBox(m_last);
49         m_last = textBox;
50     }
51     textBox->setBehavesLikeText(true);
52     return textBox;
53 }
54
55 void RenderTextLineBoxes::extract(InlineTextBox& box)
56 {
57     checkConsistency();
58
59     m_last = box.prevTextBox();
60     if (&box == m_first)
61         m_first = nullptr;
62     if (box.prevTextBox())
63         box.prevTextBox()->setNextTextBox(nullptr);
64     box.setPreviousTextBox(nullptr);
65     for (auto current = &box; current; current = current->nextTextBox())
66         current->setExtracted();
67
68     checkConsistency();
69 }
70
71 void RenderTextLineBoxes::attach(InlineTextBox& box)
72 {
73     checkConsistency();
74
75     if (m_last) {
76         m_last->setNextTextBox(&box);
77         box.setPreviousTextBox(m_last);
78     } else
79         m_first = &box;
80     InlineTextBox* last = nullptr;
81     for (auto current = &box; current; current = current->nextTextBox()) {
82         current->setExtracted(false);
83         last = current;
84     }
85     m_last = last;
86
87     checkConsistency();
88 }
89
90 void RenderTextLineBoxes::remove(InlineTextBox& box)
91 {
92     checkConsistency();
93
94     if (&box == m_first)
95         m_first = box.nextTextBox();
96     if (&box == m_last)
97         m_last = box.prevTextBox();
98     if (box.nextTextBox())
99         box.nextTextBox()->setPreviousTextBox(box.prevTextBox());
100     if (box.prevTextBox())
101         box.prevTextBox()->setNextTextBox(box.nextTextBox());
102
103     checkConsistency();
104 }
105
106 void RenderTextLineBoxes::deleteAll(RenderText& renderer)
107 {
108     if (!m_first)
109         return;
110     auto& arena = renderer.renderArena();
111     InlineTextBox* next;
112     for (auto current = m_first; current; current = next) {
113         next = current->nextTextBox();
114         current->destroy(arena);
115     }
116     m_first = nullptr;
117     m_last = nullptr;
118 }
119
120 InlineTextBox* RenderTextLineBoxes::findNext(int offset, int& position) const
121 {
122     if (!m_first)
123         return nullptr;
124     // FIXME: This looks buggy. The function is only used for debugging purposes.
125     auto current = m_first;
126     int currentOffset = current->len();
127     while (offset > currentOffset && current->nextTextBox()) {
128         current = current->nextTextBox();
129         currentOffset = current->start() + current->len();
130     }
131     // we are now in the correct text run
132     position = (offset > currentOffset ? current->len() : current->len() - (currentOffset - offset));
133     return current;
134 }
135
136 IntRect RenderTextLineBoxes::boundingBox(const RenderText& renderer) const
137 {
138     if (!m_first)
139         return IntRect();
140
141     // Return the width of the minimal left side and the maximal right side.
142     float logicalLeftSide = 0;
143     float logicalRightSide = 0;
144     for (auto current = m_first; current; current = current->nextTextBox()) {
145         if (current == m_first || current->logicalLeft() < logicalLeftSide)
146             logicalLeftSide = current->logicalLeft();
147         if (current == m_first || current->logicalRight() > logicalRightSide)
148             logicalRightSide = current->logicalRight();
149     }
150     
151     bool isHorizontal = renderer.style()->isHorizontalWritingMode();
152     
153     float x = isHorizontal ? logicalLeftSide : m_first->x();
154     float y = isHorizontal ? m_first->y() : logicalLeftSide;
155     float width = isHorizontal ? logicalRightSide - logicalLeftSide : m_last->logicalBottom() - x;
156     float height = isHorizontal ? m_last->logicalBottom() - y : logicalRightSide - logicalLeftSide;
157     return enclosingIntRect(FloatRect(x, y, width, height));
158 }
159
160 LayoutRect RenderTextLineBoxes::visualOverflowBoundingBox(const RenderText& renderer) const
161 {
162     if (!m_first)
163         return LayoutRect();
164
165     // Return the width of the minimal left side and the maximal right side.
166     auto logicalLeftSide = LayoutUnit::max();
167     auto logicalRightSide = LayoutUnit::min();
168     for (auto current = m_first; current; current = current->nextTextBox()) {
169         logicalLeftSide = std::min(logicalLeftSide, current->logicalLeftVisualOverflow());
170         logicalRightSide = std::max(logicalRightSide, current->logicalRightVisualOverflow());
171     }
172     
173     auto logicalTop = m_first->logicalTopVisualOverflow();
174     auto logicalWidth = logicalRightSide - logicalLeftSide;
175     auto logicalHeight = m_last->logicalBottomVisualOverflow() - logicalTop;
176     
177     LayoutRect rect(logicalLeftSide, logicalTop, logicalWidth, logicalHeight);
178     if (!renderer.style()->isHorizontalWritingMode())
179         rect = rect.transposedRect();
180     return rect;
181 }
182
183 bool RenderTextLineBoxes::hasRenderedText() const
184 {
185     for (auto box = m_first; box; box = box->nextTextBox()) {
186         if (box->len())
187             return true;
188     }
189     return false;
190 }
191
192 int RenderTextLineBoxes::caretMinOffset() const
193 {
194     auto box = m_first;
195     if (!box)
196         return 0;
197     int minOffset = box->start();
198     for (box = box->nextTextBox(); box; box = box->nextTextBox())
199         minOffset = std::min<int>(minOffset, box->start());
200     return minOffset;
201 }
202
203 int RenderTextLineBoxes::caretMaxOffset(const RenderText& renderer) const
204 {
205     auto box = m_last;
206     if (!box)
207         return renderer.textLength();
208
209     int maxOffset = box->start() + box->len();
210     for (box = box->prevTextBox(); box; box = box->prevTextBox())
211         maxOffset = std::max<int>(maxOffset, box->start() + box->len());
212     return maxOffset;
213 }
214
215 #if !ASSERT_DISABLED
216 RenderTextLineBoxes::~RenderTextLineBoxes()
217 {
218     ASSERT(!m_first);
219     ASSERT(!m_last);
220 }
221
222 void RenderTextLineBoxes::checkConsistency() const
223 {
224 #ifdef CHECK_CONSISTENCY
225     const InlineTextBox* prev = nullptr;
226     for (auto child = m_first; child; child = child->nextTextBox()) {
227         ASSERT(child->renderer() == this);
228         ASSERT(child->prevTextBox() == prev);
229         prev = child;
230     }
231     ASSERT(prev == m_last);
232 #endif
233 }
234 #endif
235
236 }