Simple line layout(regression): Calling innerText on RenderFlow with multiple childre...
[WebKit-https.git] / Source / WebCore / rendering / SimpleLineLayoutResolver.cpp
1 /*
2  * Copyright (C) 2014 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 "SimpleLineLayoutResolver.h"
28
29 #include "RenderBlockFlow.h"
30 #include "RenderObject.h"
31 #include "SimpleLineLayoutFunctions.h"
32
33 namespace WebCore {
34 namespace SimpleLineLayout {
35
36 static float baselinePosition(float lineHeight, float baseline, int lineIndex)
37 {
38     return lineHeight * lineIndex + baseline;
39 }
40
41 static LayoutPoint linePosition(float logicalLeft, float logicalTop)
42 {
43     return LayoutPoint(LayoutUnit::fromFloatFloor(logicalLeft), roundToInt(logicalTop));
44 }
45
46 static LayoutSize lineSize(float logicalLeft, float logicalRight, float height)
47 {
48     return LayoutSize(LayoutUnit::fromFloatCeil(logicalRight) - LayoutUnit::fromFloatFloor(logicalLeft), height);
49 }
50
51 RunResolver::Run::Run(const Iterator& iterator)
52     : m_iterator(iterator)
53 {
54 }
55
56 LayoutRect RunResolver::Run::rect() const
57 {
58     auto& run = m_iterator.simpleRun();
59     auto& resolver = m_iterator.resolver();
60     float baseline = baselinePosition(resolver.m_lineHeight, resolver.m_baseline, m_iterator.lineIndex());
61     LayoutPoint position = linePosition(run.logicalLeft, baseline - resolver.m_ascent + resolver.m_borderAndPaddingBefore);
62     LayoutSize size = lineSize(run.logicalLeft, run.logicalRight, resolver.m_ascent + resolver.m_descent);
63     return LayoutRect(position, size);
64 }
65
66 FloatPoint RunResolver::Run::baseline() const
67 {
68     auto& resolver = m_iterator.resolver();
69     auto& run = m_iterator.simpleRun();
70
71     float baseline = baselinePosition(resolver.m_lineHeight, resolver.m_baseline, m_iterator.lineIndex());
72     return FloatPoint(run.logicalLeft, roundToInt(baseline + resolver.m_borderAndPaddingBefore));
73 }
74
75 StringView RunResolver::Run::text() const
76 {
77     auto& resolver = m_iterator.resolver();
78     auto& run = m_iterator.simpleRun();
79     ASSERT(run.start < run.end);
80     auto& segment = resolver.m_flowContents.segmentForRun(run.start, run.end);
81     // We currently split runs on segment boundaries (different RenderObject).
82     ASSERT(run.end <= segment.end);
83     if (segment.text.is8Bit())
84         return StringView(segment.text.characters8(), segment.text.length()).substring(run.start - segment.start, run.end - run.start);
85     return StringView(segment.text.characters16(), segment.text.length()).substring(run.start - segment.start, run.end - run.start);
86 }
87
88 RunResolver::Iterator::Iterator(const RunResolver& resolver, unsigned runIndex, unsigned lineIndex)
89     : m_resolver(resolver)
90     , m_runIndex(runIndex)
91     , m_lineIndex(lineIndex)
92 {
93 }
94
95 RunResolver::Iterator& RunResolver::Iterator::advance()
96 {
97     if (simpleRun().isEndOfLine)
98         ++m_lineIndex;
99     ++m_runIndex;
100     return *this;
101 }
102
103 RunResolver::Iterator& RunResolver::Iterator::advanceLines(unsigned lineCount)
104 {
105     unsigned runCount = m_resolver.m_layout.runCount();
106     if (runCount == m_resolver.m_layout.lineCount()) {
107         m_runIndex = std::min(runCount, m_runIndex + lineCount);
108         m_lineIndex = m_runIndex;
109         return *this;
110     }
111     unsigned target = m_lineIndex + lineCount;
112     while (m_lineIndex < target && m_runIndex < runCount)
113         advance();
114
115     return *this;
116 }
117
118 RunResolver::RunResolver(const RenderBlockFlow& flow, const Layout& layout)
119     : m_flowRenderer(flow)
120     , m_layout(layout)
121     , m_flowContents(flow)
122     , m_lineHeight(lineHeightFromFlow(flow))
123     , m_baseline(baselineFromFlow(flow))
124     , m_borderAndPaddingBefore(flow.borderAndPaddingBefore())
125     , m_ascent(flow.style().fontCascade().fontMetrics().ascent())
126     , m_descent(flow.style().fontCascade().fontMetrics().descent())
127 {
128 }
129
130 unsigned RunResolver::lineIndexForHeight(LayoutUnit height, IndexType type) const
131 {
132     ASSERT(m_lineHeight);
133     float y = height - m_borderAndPaddingBefore;
134     // Lines may overlap, adjust to get the first or last line at this height.
135     if (type == IndexType::First)
136         y += m_lineHeight - (m_baseline + m_descent);
137     else
138         y -= m_baseline - m_ascent;
139     y = std::max<float>(y, 0);
140     return std::min<unsigned>(y / m_lineHeight, m_layout.lineCount() - 1);
141 }
142
143 Range<RunResolver::Iterator> RunResolver::rangeForRect(const LayoutRect& rect) const
144
145     if (!m_lineHeight)
146         return Range<Iterator>(begin(), end());
147
148     unsigned firstLine = lineIndexForHeight(rect.y(), IndexType::First);
149     unsigned lastLine = std::max(firstLine, lineIndexForHeight(rect.maxY(), IndexType::Last));
150
151     auto rangeBegin = begin().advanceLines(firstLine);
152     if (rangeBegin == end())
153         return Range<Iterator>(end(), end());
154     auto rangeEnd = rangeBegin;
155     ASSERT(lastLine >= firstLine);
156     rangeEnd.advanceLines(lastLine - firstLine + 1);
157     return Range<Iterator>(rangeBegin, rangeEnd);
158 }
159
160 Range<RunResolver::Iterator> RunResolver::rangeForRenderer(const RenderObject& renderer) const
161 {
162     auto& segment = m_flowContents.segmentForRenderer(renderer);
163
164     auto rangeBegin = begin();
165     for (;rangeBegin != end() && (*rangeBegin).start() < segment.start; ++rangeBegin) { }
166
167     auto rangeEnd = rangeBegin;
168     for (;rangeEnd != end() && (*rangeEnd).end() <= segment.end; ++rangeEnd) { }
169
170     return Range<Iterator>(rangeBegin, rangeEnd);
171 }
172
173 LineResolver::Iterator::Iterator(RunResolver::Iterator runIterator)
174     : m_runIterator(runIterator)
175 {
176 }
177
178 const LayoutRect LineResolver::Iterator::operator*() const
179 {
180     unsigned currentLine = m_runIterator.lineIndex();
181     auto it = m_runIterator;
182     LayoutRect rect = (*it).rect();
183     while (it.advance().lineIndex() == currentLine)
184         rect.unite((*it).rect());
185
186     return rect;
187 }
188
189 LineResolver::LineResolver(const RenderBlockFlow& flow, const Layout& layout)
190     : m_runResolver(flow, layout)
191 {
192 }
193
194 }
195 }