source: webkit/trunk/Source/WebCore/rendering/RenderLineBreak.cpp

Last change on this file was 293497, checked in by Antti Koivisto, 3 years ago

::first-letter does not work if used only in shadow content
https://bugs.webkit.org/show_bug.cgi?id=220650
<rdar://problem/73477161>

Reviewed by Alan Bujtas.

Source/WebCore:

Test: fast/shadow-dom/shadow-first-line-and-letter.html

We were not setting usesFirstLetter/LinesRules bits if those pseudo-elements were used
only in shadow trees.

Fix by removing the bits. They don't seem to allow any valuable optimizations.

  • rendering/LegacyRootInlineBox.cpp:

(WebCore::LegacyRootInlineBox::verticalPositionForBox):

  • rendering/RenderBlock.cpp:

(WebCore::RenderBlock::lineHeight const):
(WebCore::RenderBlock::getFirstLetter):

  • rendering/RenderInline.cpp:

(WebCore::RenderInline::mayAffectLayout const):
(WebCore::RenderInline::lineHeight const):

  • rendering/RenderLineBreak.cpp:

(WebCore::RenderLineBreak::lineHeight const):

  • rendering/RenderView.h:
  • style/StyleTreeResolver.cpp:

(WebCore::Style::TreeResolver::createAnimatedElementUpdate):
(WebCore::Style::TreeResolver::resolve):

LayoutTests:

Test case by [email protected].

  • fast/shadow-dom/shadow-first-line-and-letter-expected.html: Added.
  • fast/shadow-dom/shadow-first-line-and-letter.html: Added.
  • Property svn:eol-style set to native
File size: 8.3 KB
Line 
1/**
2 * Copyright (C) 2000 Lars Knoll ([email protected])
3 * Copyright (C) 2006, 2013 Apple Inc. All rights reserved.
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
14 *
15 * You should have received a copy of the GNU Library General Public License
16 * along with this library; see the file COPYING.LIB. If not, write to
17 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
19 *
20 */
21
22#include "config.h"
23#include "RenderLineBreak.h"
24
25#include "Document.h"
26#include "FontMetrics.h"
27#include "HTMLElement.h"
28#include "HTMLWBRElement.h"
29#include "InlineIteratorBox.h"
30#include "InlineIteratorLineBox.h"
31#include "InlineRunAndOffset.h"
32#include "LegacyInlineElementBox.h"
33#include "LegacyRootInlineBox.h"
34#include "LineSelection.h"
35#include "LogicalSelectionOffsetCaches.h"
36#include "RenderBlock.h"
37#include "RenderView.h"
38#include "SVGElementTypeHelpers.h"
39#include "SVGInlineTextBox.h"
40#include "VisiblePosition.h"
41#include <wtf/IsoMallocInlines.h>
42
43#if PLATFORM(IOS_FAMILY)
44#include "SelectionGeometry.h"
45#endif
46
47namespace WebCore {
48
49WTF_MAKE_ISO_ALLOCATED_IMPL(RenderLineBreak);
50
51static const int invalidLineHeight = -1;
52
53RenderLineBreak::RenderLineBreak(HTMLElement& element, RenderStyle&& style)
54 : RenderBoxModelObject(element, WTFMove(style), 0)
55 , m_inlineBoxWrapper(nullptr)
56 , m_cachedLineHeight(invalidLineHeight)
57 , m_isWBR(is<HTMLWBRElement>(element))
58{
59 setIsLineBreak();
60}
61
62RenderLineBreak::~RenderLineBreak()
63{
64 delete m_inlineBoxWrapper;
65}
66
67LayoutUnit RenderLineBreak::lineHeight(bool firstLine, LineDirectionMode /*direction*/, LinePositionMode /*linePositionMode*/) const
68{
69 if (firstLine) {
70 const RenderStyle& firstLineStyle = this->firstLineStyle();
71 if (&firstLineStyle != &style())
72 return firstLineStyle.computedLineHeight();
73 }
74
75 if (m_cachedLineHeight == invalidLineHeight)
76 m_cachedLineHeight = style().computedLineHeight();
77
78 return m_cachedLineHeight;
79}
80
81LayoutUnit RenderLineBreak::baselinePosition(FontBaseline baselineType, bool firstLine, LineDirectionMode direction, LinePositionMode linePositionMode) const
82{
83 const RenderStyle& style = firstLine ? firstLineStyle() : this->style();
84 const FontMetrics& fontMetrics = style.metricsOfPrimaryFont();
85 return LayoutUnit { (fontMetrics.ascent(baselineType) + (lineHeight(firstLine, direction, linePositionMode) - fontMetrics.height()) / 2).toInt() };
86}
87
88std::unique_ptr<LegacyInlineElementBox> RenderLineBreak::createInlineBox()
89{
90 return makeUnique<LegacyInlineElementBox>(*this);
91}
92
93void RenderLineBreak::setInlineBoxWrapper(LegacyInlineElementBox* inlineBox)
94{
95 ASSERT(!inlineBox || !m_inlineBoxWrapper);
96 m_inlineBoxWrapper = inlineBox;
97}
98
99void RenderLineBreak::replaceInlineBoxWrapper(LegacyInlineElementBox& inlineBox)
100{
101 deleteInlineBoxWrapper();
102 setInlineBoxWrapper(&inlineBox);
103}
104
105void RenderLineBreak::deleteInlineBoxWrapper()
106{
107 if (!m_inlineBoxWrapper)
108 return;
109 if (!renderTreeBeingDestroyed())
110 m_inlineBoxWrapper->removeFromParent();
111 delete m_inlineBoxWrapper;
112 m_inlineBoxWrapper = nullptr;
113}
114
115void RenderLineBreak::dirtyLineBoxes(bool fullLayout)
116{
117 if (!m_inlineBoxWrapper)
118 return;
119 if (fullLayout) {
120 delete m_inlineBoxWrapper;
121 m_inlineBoxWrapper = nullptr;
122 return;
123 }
124 m_inlineBoxWrapper->dirtyLineBoxes();
125}
126
127int RenderLineBreak::caretMinOffset() const
128{
129 return 0;
130}
131
132int RenderLineBreak::caretMaxOffset() const
133{
134 return 1;
135}
136
137bool RenderLineBreak::canBeSelectionLeaf() const
138{
139 return true;
140}
141
142VisiblePosition RenderLineBreak::positionForPoint(const LayoutPoint&, const RenderFragmentContainer*)
143{
144 return createVisiblePosition(0, Affinity::Downstream);
145}
146
147IntRect RenderLineBreak::linesBoundingBox() const
148{
149 auto run = InlineIterator::boxFor(*this);
150 if (!run)
151 return { };
152
153 return enclosingIntRect(run->visualRectIgnoringBlockDirection());
154}
155
156void RenderLineBreak::absoluteRects(Vector<IntRect>& rects, const LayoutPoint& accumulatedOffset) const
157{
158 auto box = InlineIterator::boxFor(*this);
159 if (!box)
160 return;
161
162 auto rect = box->visualRectIgnoringBlockDirection();
163 rects.append(enclosingIntRect(FloatRect(accumulatedOffset + rect.location(), rect.size())));
164}
165
166void RenderLineBreak::absoluteQuads(Vector<FloatQuad>& quads, bool* wasFixed) const
167{
168 auto box = InlineIterator::boxFor(*this);
169 if (!box)
170 return;
171
172 auto rect = box->visualRectIgnoringBlockDirection();
173 quads.append(localToAbsoluteQuad(FloatRect(rect.location(), rect.size()), UseTransforms, wasFixed));
174}
175
176void RenderLineBreak::updateFromStyle()
177{
178 m_cachedLineHeight = invalidLineHeight;
179 RELEASE_ASSERT_WITH_SECURITY_IMPLICATION(isInline());
180}
181
182#if PLATFORM(IOS_FAMILY)
183void RenderLineBreak::collectSelectionGeometries(Vector<SelectionGeometry>& rects, unsigned, unsigned)
184{
185 auto run = InlineIterator::boxFor(*this);
186
187 if (!run)
188 return;
189 auto lineBox = run->lineBox();
190
191 auto lineSelectionRect = LineSelection::logicalRect(*lineBox);
192 LayoutRect rect = IntRect(run->logicalLeft(), lineSelectionRect.y(), 0, lineSelectionRect.height());
193 if (!lineBox->isHorizontal())
194 rect = rect.transposedRect();
195
196 if (lineBox->isFirstAfterPageBreak()) {
197 if (run->isHorizontal())
198 rect.shiftYEdgeTo(lineBox->top());
199 else
200 rect.shiftXEdgeTo(lineBox->top());
201 }
202
203 // FIXME: Out-of-flow positioned line breaks do not follow normal containing block chain.
204 auto* containingBlock = RenderObject::containingBlockForPositionType(PositionType::Static, *this);
205 // Map rect, extended left to leftOffset, and right to rightOffset, through transforms to get minX and maxX.
206 LogicalSelectionOffsetCaches cache(*containingBlock);
207 LayoutUnit leftOffset = containingBlock->logicalLeftSelectionOffset(*containingBlock, LayoutUnit(run->logicalTop()), cache);
208 LayoutUnit rightOffset = containingBlock->logicalRightSelectionOffset(*containingBlock, LayoutUnit(run->logicalTop()), cache);
209 LayoutRect extentsRect = rect;
210 if (run->isHorizontal()) {
211 extentsRect.setX(leftOffset);
212 extentsRect.setWidth(rightOffset - leftOffset);
213 } else {
214 extentsRect.setY(leftOffset);
215 extentsRect.setHeight(rightOffset - leftOffset);
216 }
217 extentsRect = localToAbsoluteQuad(FloatRect(extentsRect)).enclosingBoundingBox();
218 if (!run->isHorizontal())
219 extentsRect = extentsRect.transposedRect();
220 bool isFirstOnLine = !run->previousOnLine();
221 bool isLastOnLine = !run->nextOnLine();
222 if (containingBlock->isRubyBase() || containingBlock->isRubyText())
223 isLastOnLine = !containingBlock->containingBlock()->inlineBoxWrapper()->nextOnLineExists();
224
225 bool isFixed = false;
226 auto absoluteQuad = localToAbsoluteQuad(FloatRect(rect), UseTransforms, &isFixed);
227 bool boxIsHorizontal = !is<SVGInlineTextBox>(run->legacyInlineBox()) ? run->isHorizontal() : !style().isVerticalWritingMode();
228 // If the containing block is an inline element, we want to check the inlineBoxWrapper orientation
229 // to determine the orientation of the block. In this case we also use the inlineBoxWrapper to
230 // determine if the element is the last on the line.
231 if (containingBlock->inlineBoxWrapper()) {
232 if (containingBlock->inlineBoxWrapper()->isHorizontal() != boxIsHorizontal) {
233 boxIsHorizontal = containingBlock->inlineBoxWrapper()->isHorizontal();
234 isLastOnLine = !containingBlock->inlineBoxWrapper()->nextOnLineExists();
235 }
236 }
237
238 rects.append(SelectionGeometry(absoluteQuad, HTMLElement::selectionRenderingBehavior(element()), run->direction(), extentsRect.x(), extentsRect.maxX(), extentsRect.maxY(), 0, run->isLineBreak(), isFirstOnLine, isLastOnLine, false, false, boxIsHorizontal, isFixed, containingBlock->isRubyText(), view().pageNumberForBlockProgressionOffset(absoluteQuad.enclosingBoundingBox().x())));
239}
240#endif
241
242} // namespace WebCore
Note: See TracBrowser for help on using the repository browser.