2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3 * (C) 1999 Antti Koivisto (koivisto@kde.org)
4 * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
16 * You should have received a copy of the GNU Library General Public License
17 * along with this library; see the file COPYING.LIB. If not, write to
18 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301, USA.
24 #include "core/layout/LayoutInline.h"
26 #include "core/dom/Fullscreen.h"
27 #include "core/dom/StyleEngine.h"
28 #include "core/layout/HitTestResult.h"
29 #include "core/layout/LayoutBlock.h"
30 #include "core/layout/LayoutFlowThread.h"
31 #include "core/layout/LayoutFullScreen.h"
32 #include "core/layout/LayoutGeometryMap.h"
33 #include "core/layout/LayoutTheme.h"
34 #include "core/layout/LayoutView.h"
35 #include "core/layout/api/LineLayoutBoxModel.h"
36 #include "core/layout/line/InlineTextBox.h"
37 #include "core/paint/BoxPainter.h"
38 #include "core/paint/DeprecatedPaintLayer.h"
39 #include "core/paint/InlinePainter.h"
40 #include "core/paint/ObjectPainter.h"
41 #include "core/style/StyleInheritedData.h"
42 #include "platform/geometry/FloatQuad.h"
43 #include "platform/geometry/Region.h"
44 #include "platform/geometry/TransformState.h"
48 struct SameSizeAsLayoutInline
: public LayoutBoxModelObject
{
49 virtual ~SameSizeAsLayoutInline() { }
50 LayoutObjectChildList m_children
;
51 LineBoxList m_lineBoxes
;
54 static_assert(sizeof(LayoutInline
) == sizeof(SameSizeAsLayoutInline
), "LayoutInline should stay small");
56 LayoutInline::LayoutInline(Element
* element
)
57 : LayoutBoxModelObject(element
)
59 setChildrenInline(true);
62 LayoutInline
* LayoutInline::createAnonymous(Document
* document
)
64 LayoutInline
* layoutObject
= new LayoutInline(nullptr);
65 layoutObject
->setDocumentForAnonymous(document
);
69 void LayoutInline::willBeDestroyed()
71 // Make sure to destroy anonymous children first while they are still connected to the rest of the tree, so that they will
72 // properly dirty line boxes that they are removed from. Effects that do :before/:after only on hover could crash otherwise.
73 children()->destroyLeftoverChildren();
75 // Destroy our continuation before anything other than anonymous children.
76 // The reason we don't destroy it before anonymous children is that they may
77 // have continuations of their own that are anonymous children of our continuation.
78 LayoutBoxModelObject
* continuation
= this->continuation();
80 continuation
->destroy();
81 setContinuation(nullptr);
84 if (!documentBeingDestroyed()) {
86 // We can't wait for LayoutBoxModelObject::destroy to clear the selection,
87 // because by then we will have nuked the line boxes.
88 // FIXME: The FrameSelection should be responsible for this when it
89 // is notified of DOM mutations.
90 if (isSelectionBorder())
91 view()->clearSelection();
93 // If line boxes are contained inside a root, that means we're an inline.
94 // In that case, we need to remove all the line boxes so that the parent
95 // lines aren't pointing to deleted children. If the first line box does
96 // not have a parent that means they are either already disconnected or
97 // root lines that can just be destroyed without disconnecting.
98 if (firstLineBox()->parent()) {
99 for (InlineFlowBox
* box
= firstLineBox(); box
; box
= box
->nextLineBox())
102 } else if (parent()) {
103 parent()->dirtyLinesFromChangedChild(this);
107 m_lineBoxes
.deleteLineBoxes();
109 LayoutBoxModelObject::willBeDestroyed();
112 LayoutInline
* LayoutInline::inlineElementContinuation() const
114 LayoutBoxModelObject
* continuation
= this->continuation();
115 if (!continuation
|| continuation
->isInline())
116 return toLayoutInline(continuation
);
117 return toLayoutBlock(continuation
)->inlineElementContinuation();
120 void LayoutInline::updateFromStyle()
122 LayoutBoxModelObject::updateFromStyle();
124 // FIXME: Is this still needed. Was needed for run-ins, since run-in is considered a block display type.
127 // FIXME: Support transforms and reflections on inline flows someday.
128 setHasTransformRelatedProperty(false);
129 setHasReflection(false);
132 static LayoutObject
* inFlowPositionedInlineAncestor(LayoutObject
* p
)
134 while (p
&& p
->isLayoutInline()) {
135 if (p
->isInFlowPositioned())
142 static void updateInFlowPositionOfAnonymousBlockContinuations(LayoutObject
* block
, const ComputedStyle
& newStyle
, const ComputedStyle
& oldStyle
, LayoutObject
* containingBlockOfEndOfContinuation
)
144 for (; block
&& block
!= containingBlockOfEndOfContinuation
&& block
->isAnonymousBlock(); block
= block
->nextSibling()) {
145 if (!toLayoutBlock(block
)->isAnonymousBlockContinuation())
148 // If we are no longer in-flow positioned but our descendant block(s) still have an in-flow positioned ancestor then
149 // their containing anonymous block should keep its in-flow positioning.
150 if (oldStyle
.hasInFlowPosition() && inFlowPositionedInlineAncestor(toLayoutBlock(block
)->inlineElementContinuation()))
153 RefPtr
<ComputedStyle
> newBlockStyle
= ComputedStyle::clone(block
->styleRef());
154 newBlockStyle
->setPosition(newStyle
.position());
155 block
->setStyle(newBlockStyle
);
159 void LayoutInline::styleDidChange(StyleDifference diff
, const ComputedStyle
* oldStyle
)
161 LayoutBoxModelObject::styleDidChange(diff
, oldStyle
);
163 // Ensure that all of the split inlines pick up the new style. We
164 // only do this if we're an inline, since we don't want to propagate
165 // a block's style to the other inlines.
166 // e.g., <font>foo <h4>goo</h4> moo</font>. The <font> inlines before
167 // and after the block share the same style, but the block doesn't
168 // need to pass its style on to anyone else.
169 const ComputedStyle
& newStyle
= styleRef();
170 LayoutInline
* continuation
= inlineElementContinuation();
171 LayoutInline
* endOfContinuation
= nullptr;
172 for (LayoutInline
* currCont
= continuation
; currCont
; currCont
= currCont
->inlineElementContinuation()) {
173 LayoutBoxModelObject
* nextCont
= currCont
->continuation();
174 currCont
->setContinuation(nullptr);
175 currCont
->setStyle(mutableStyle());
176 currCont
->setContinuation(nextCont
);
177 endOfContinuation
= currCont
;
180 if (continuation
&& oldStyle
) {
181 ASSERT(endOfContinuation
);
182 LayoutObject
* block
= containingBlock()->nextSibling();
183 // If an inline's in-flow positioning has changed then any descendant blocks will need to change their styles accordingly.
184 if (block
&& block
->isAnonymousBlock()
185 && newStyle
.position() != oldStyle
->position()
186 && (newStyle
.hasInFlowPosition() || oldStyle
->hasInFlowPosition()))
187 updateInFlowPositionOfAnonymousBlockContinuations(block
, newStyle
, *oldStyle
, endOfContinuation
->containingBlock());
190 if (!alwaysCreateLineBoxes()) {
191 bool alwaysCreateLineBoxesNew
= hasSelfPaintingLayer() || hasBoxDecorationBackground() || newStyle
.hasPadding() || newStyle
.hasMargin() || newStyle
.hasOutline();
192 if (oldStyle
&& alwaysCreateLineBoxesNew
) {
193 dirtyLineBoxes(false);
194 setNeedsLayoutAndFullPaintInvalidation(LayoutInvalidationReason::StyleChange
);
196 setAlwaysCreateLineBoxes(alwaysCreateLineBoxesNew
);
200 void LayoutInline::updateAlwaysCreateLineBoxes(bool fullLayout
)
202 // Once we have been tainted once, just assume it will happen again. This way effects like hover highlighting that change the
203 // background color will only cause a layout on the first rollover.
204 if (alwaysCreateLineBoxes())
207 const ComputedStyle
& parentStyle
= parent()->styleRef();
208 LayoutInline
* parentLayoutInline
= parent()->isLayoutInline() ? toLayoutInline(parent()) : 0;
209 bool checkFonts
= document().inNoQuirksMode();
210 bool alwaysCreateLineBoxesNew
= (parentLayoutInline
&& parentLayoutInline
->alwaysCreateLineBoxes())
211 || (parentLayoutInline
&& parentStyle
.verticalAlign() != BASELINE
)
212 || style()->verticalAlign() != BASELINE
213 || style()->textEmphasisMark() != TextEmphasisMarkNone
214 || (checkFonts
&& (!parentStyle
.font().fontMetrics().hasIdenticalAscentDescentAndLineGap(style()->font().fontMetrics())
215 || parentStyle
.lineHeight() != style()->lineHeight()));
217 if (!alwaysCreateLineBoxesNew
&& checkFonts
&& document().styleEngine().usesFirstLineRules()) {
218 // Have to check the first line style as well.
219 const ComputedStyle
& firstLineParentStyle
= parent()->styleRef(true);
220 const ComputedStyle
& childStyle
= styleRef(true);
221 alwaysCreateLineBoxesNew
= !firstLineParentStyle
.font().fontMetrics().hasIdenticalAscentDescentAndLineGap(childStyle
.font().fontMetrics())
222 || childStyle
.verticalAlign() != BASELINE
223 || firstLineParentStyle
.lineHeight() != childStyle
.lineHeight();
226 if (alwaysCreateLineBoxesNew
) {
228 dirtyLineBoxes(false);
229 setAlwaysCreateLineBoxes();
233 LayoutRect
LayoutInline::localCaretRect(InlineBox
* inlineBox
, int, LayoutUnit
* extraWidthToEndOfLine
)
236 // This condition is possible if the LayoutInline is at an editing boundary,
237 // i.e. the VisiblePosition is:
238 // <LayoutInline editingBoundary=true>|<LayoutText> </LayoutText></LayoutInline>
239 // FIXME: need to figure out how to make this return a valid rect, note that
240 // there are no line boxes created in the above case.
244 ASSERT_UNUSED(inlineBox
, !inlineBox
);
246 if (extraWidthToEndOfLine
)
247 *extraWidthToEndOfLine
= 0;
249 LayoutRect caretRect
= localCaretRectForEmptyElement(borderAndPaddingWidth(), 0);
251 if (InlineBox
* firstBox
= firstLineBox()) {
252 // FIXME: the call to roundedLayoutPoint() below is temporary and should be removed once
253 // the transition to LayoutUnit-based types is complete (crbug.com/321237)
254 caretRect
.moveBy(firstBox
->topLeft());
260 void LayoutInline::addChild(LayoutObject
* newChild
, LayoutObject
* beforeChild
)
263 return addChildToContinuation(newChild
, beforeChild
);
264 return addChildIgnoringContinuation(newChild
, beforeChild
);
267 static LayoutBoxModelObject
* nextContinuation(LayoutObject
* layoutObject
)
269 if (layoutObject
->isInline() && !layoutObject
->isReplaced())
270 return toLayoutInline(layoutObject
)->continuation();
271 return toLayoutBlock(layoutObject
)->inlineElementContinuation();
274 LayoutBoxModelObject
* LayoutInline::continuationBefore(LayoutObject
* beforeChild
)
276 if (beforeChild
&& beforeChild
->parent() == this)
279 LayoutBoxModelObject
* curr
= nextContinuation(this);
280 LayoutBoxModelObject
* nextToLast
= this;
281 LayoutBoxModelObject
* last
= this;
283 if (beforeChild
&& beforeChild
->parent() == curr
) {
284 if (curr
->slowFirstChild() == beforeChild
)
291 curr
= nextContinuation(curr
);
294 if (!beforeChild
&& !last
->slowFirstChild())
299 void LayoutInline::addChildIgnoringContinuation(LayoutObject
* newChild
, LayoutObject
* beforeChild
)
301 // Make sure we don't append things after :after-generated content if we have it.
302 if (!beforeChild
&& isAfterContent(lastChild()))
303 beforeChild
= lastChild();
305 if (!newChild
->isInline() && !newChild
->isFloatingOrOutOfFlowPositioned()) {
306 // We are placing a block inside an inline. We have to perform a split of this
307 // inline into continuations. This involves creating an anonymous block box to hold
308 // |newChild|. We then make that block box a continuation of this inline. We take all of
309 // the children after |beforeChild| and put them in a clone of this object.
310 RefPtr
<ComputedStyle
> newStyle
= ComputedStyle::createAnonymousStyleWithDisplay(styleRef(), BLOCK
);
312 // If inside an inline affected by in-flow positioning the block needs to be affected by it too.
313 // Giving the block a layer like this allows it to collect the x/y offsets from inline parents later.
314 if (LayoutObject
* positionedAncestor
= inFlowPositionedInlineAncestor(this))
315 newStyle
->setPosition(positionedAncestor
->style()->position());
317 LayoutBlockFlow
* newBox
= LayoutBlockFlow::createAnonymous(&document());
318 newBox
->setStyle(newStyle
.release());
319 LayoutBoxModelObject
* oldContinuation
= continuation();
320 setContinuation(newBox
);
322 splitFlow(beforeChild
, newBox
, newChild
, oldContinuation
);
326 LayoutBoxModelObject::addChild(newChild
, beforeChild
);
328 newChild
->setNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation(LayoutInvalidationReason::ChildChanged
);
331 LayoutInline
* LayoutInline::clone() const
333 LayoutInline
* cloneInline
= new LayoutInline(node());
334 cloneInline
->setStyle(mutableStyle());
335 cloneInline
->setIsInsideFlowThread(isInsideFlowThread());
339 void LayoutInline::moveChildrenToIgnoringContinuation(LayoutInline
* to
, LayoutObject
* startChild
)
341 LayoutObject
* child
= startChild
;
343 LayoutObject
* currentChild
= child
;
344 child
= currentChild
->nextSibling();
345 to
->addChildIgnoringContinuation(children()->removeChildNode(this, currentChild
), nullptr);
349 void LayoutInline::splitInlines(LayoutBlock
* fromBlock
, LayoutBlock
* toBlock
,
350 LayoutBlock
* middleBlock
, LayoutObject
* beforeChild
, LayoutBoxModelObject
* oldCont
)
352 ASSERT(isDescendantOf(fromBlock
));
354 // If we're splitting the inline containing the fullscreened element,
355 // |beforeChild| may be the layoutObject for the fullscreened element. However,
356 // that layoutObject is wrapped in a LayoutFullScreen, so |this| is not its
357 // parent. Since the splitting logic expects |this| to be the parent, set
358 // |beforeChild| to be the LayoutFullScreen.
359 if (Fullscreen
* fullscreen
= Fullscreen::fromIfExists(document())) {
360 const Element
* fullScreenElement
= fullscreen
->webkitCurrentFullScreenElement();
361 if (fullScreenElement
&& beforeChild
&& beforeChild
->node() == fullScreenElement
)
362 beforeChild
= fullscreen
->fullScreenLayoutObject();
365 // FIXME: Because splitting is O(n^2) as tags nest pathologically, we cap the depth at which we're willing to clone.
366 // There will eventually be a better approach to this problem that will let us nest to a much
367 // greater depth (see bugzilla bug 13430) but for now we have a limit. This *will* result in
368 // incorrect rendering, but the alternative is to hang forever.
369 const unsigned cMaxSplitDepth
= 200;
370 Vector
<LayoutInline
*> inlinesToClone
;
371 LayoutInline
* topMostInline
= this;
372 for (LayoutObject
* o
= this; o
!= fromBlock
; o
= o
->parent()) {
373 topMostInline
= toLayoutInline(o
);
374 if (inlinesToClone
.size() < cMaxSplitDepth
)
375 inlinesToClone
.append(topMostInline
);
376 // Keep walking up the chain to ensure |topMostInline| is a child of |fromBlock|,
377 // to avoid assertion failure when |fromBlock|'s children are moved to |toBlock| below.
380 // Create a new clone of the top-most inline in |inlinesToClone|.
381 LayoutInline
* topMostInlineToClone
= inlinesToClone
.last();
382 LayoutInline
* cloneInline
= topMostInlineToClone
->clone();
384 // Now we are at the block level. We need to put the clone into the |toBlock|.
385 toBlock
->children()->appendChildNode(toBlock
, cloneInline
);
387 // Now take all the children after |topMostInline| and remove them from the |fromBlock|
388 // and put them into the toBlock.
389 fromBlock
->moveChildrenTo(toBlock
, topMostInline
->nextSibling(), nullptr, true);
391 LayoutInline
* currentParent
= topMostInlineToClone
;
392 LayoutInline
* cloneInlineParent
= cloneInline
;
394 // Clone the inlines from top to down to ensure any new object will be added into a rooted tree.
395 // Note that we have already cloned the top-most one, so the loop begins from size - 2 (except if
396 // we have reached |cMaxDepth| in which case we sacrifice correct rendering for performance).
397 for (int i
= static_cast<int>(inlinesToClone
.size()) - 2; i
>= 0; --i
) {
398 // Hook the clone up as a continuation of |currentInline|.
399 LayoutBoxModelObject
* oldCont
= currentParent
->continuation();
400 currentParent
->setContinuation(cloneInline
);
401 cloneInline
->setContinuation(oldCont
);
403 // Create a new clone.
404 LayoutInline
* current
= inlinesToClone
[i
];
405 cloneInline
= current
->clone();
407 // Insert our |cloneInline| as the first child of |cloneInlineParent|.
408 cloneInlineParent
->addChildIgnoringContinuation(cloneInline
, nullptr);
410 // Now we need to take all of the children starting from the first child
411 // *after* |current| and append them all to the |cloneInlineParent|.
412 currentParent
->moveChildrenToIgnoringContinuation(cloneInlineParent
, current
->nextSibling());
414 currentParent
= current
;
415 cloneInlineParent
= cloneInline
;
418 // The last inline to clone is |this|, and the current |cloneInline| is cloned from |this|.
419 ASSERT(this == inlinesToClone
.first());
421 // Hook |cloneInline| up as the continuation of the middle block.
422 cloneInline
->setContinuation(oldCont
);
423 middleBlock
->setContinuation(cloneInline
);
425 // Now take all of the children from |beforeChild| to the end and remove
426 // them from |this| and place them in the clone.
427 moveChildrenToIgnoringContinuation(cloneInline
, beforeChild
);
430 void LayoutInline::splitFlow(LayoutObject
* beforeChild
, LayoutBlock
* newBlockBox
,
431 LayoutObject
* newChild
, LayoutBoxModelObject
* oldCont
)
433 LayoutBlock
* pre
= nullptr;
434 LayoutBlock
* block
= containingBlock();
436 // Delete our line boxes before we do the inline split into continuations.
437 block
->deleteLineBoxTree();
439 bool madeNewBeforeBlock
= false;
440 if (block
->isAnonymousBlock() && (!block
->parent() || !block
->parent()->createsAnonymousWrapper())) {
441 // We can reuse this block and make it the preBlock of the next continuation.
443 pre
->removePositionedObjects(nullptr);
444 if (pre
->isLayoutBlockFlow())
445 toLayoutBlockFlow(pre
)->removeFloatingObjects();
446 block
= block
->containingBlock();
448 // No anonymous block available for use. Make one.
449 pre
= block
->createAnonymousBlock();
450 madeNewBeforeBlock
= true;
453 LayoutBlock
* post
= toLayoutBlock(pre
->createAnonymousBoxWithSameTypeAs(block
));
455 LayoutObject
* boxFirst
= madeNewBeforeBlock
? block
->firstChild() : pre
->nextSibling();
456 if (madeNewBeforeBlock
)
457 block
->children()->insertChildNode(block
, pre
, boxFirst
);
458 block
->children()->insertChildNode(block
, newBlockBox
, boxFirst
);
459 block
->children()->insertChildNode(block
, post
, boxFirst
);
460 block
->setChildrenInline(false);
462 if (madeNewBeforeBlock
) {
463 LayoutObject
* o
= boxFirst
;
465 LayoutObject
* no
= o
;
466 o
= no
->nextSibling();
467 pre
->children()->appendChildNode(pre
, block
->children()->removeChildNode(block
, no
));
468 no
->setNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation(LayoutInvalidationReason::AnonymousBlockChange
);
472 splitInlines(pre
, post
, newBlockBox
, beforeChild
, oldCont
);
474 // We already know the newBlockBox isn't going to contain inline kids, so avoid wasting
475 // time in makeChildrenNonInline by just setting this explicitly up front.
476 newBlockBox
->setChildrenInline(false);
478 newBlockBox
->addChild(newChild
);
480 // Always just do a full layout in order to ensure that line boxes (especially wrappers for images)
481 // get deleted properly. Because objects moves from the pre block into the post block, we want to
482 // make new line boxes instead of leaving the old line boxes around.
483 pre
->setNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation(LayoutInvalidationReason::AnonymousBlockChange
);
484 block
->setNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation(LayoutInvalidationReason::AnonymousBlockChange
);
485 post
->setNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation(LayoutInvalidationReason::AnonymousBlockChange
);
488 void LayoutInline::addChildToContinuation(LayoutObject
* newChild
, LayoutObject
* beforeChild
)
490 LayoutBoxModelObject
* flow
= continuationBefore(beforeChild
);
491 ASSERT(!beforeChild
|| beforeChild
->parent()->isLayoutBlock() || beforeChild
->parent()->isLayoutInline());
492 LayoutBoxModelObject
* beforeChildParent
= nullptr;
494 beforeChildParent
= toLayoutBoxModelObject(beforeChild
->parent());
496 LayoutBoxModelObject
* cont
= nextContinuation(flow
);
498 beforeChildParent
= cont
;
500 beforeChildParent
= flow
;
503 if (newChild
->isFloatingOrOutOfFlowPositioned())
504 return beforeChildParent
->addChildIgnoringContinuation(newChild
, beforeChild
);
506 // A continuation always consists of two potential candidates: an inline or an anonymous
507 // block box holding block children.
508 bool childInline
= newChild
->isInline();
509 bool bcpInline
= beforeChildParent
->isInline();
510 bool flowInline
= flow
->isInline();
512 if (flow
== beforeChildParent
)
513 return flow
->addChildIgnoringContinuation(newChild
, beforeChild
);
515 // The goal here is to match up if we can, so that we can coalesce and create the
516 // minimal # of continuations needed for the inline.
517 if (childInline
== bcpInline
|| (beforeChild
&& beforeChild
->isInline()))
518 return beforeChildParent
->addChildIgnoringContinuation(newChild
, beforeChild
);
519 if (flowInline
== childInline
)
520 return flow
->addChildIgnoringContinuation(newChild
, 0); // Just treat like an append.
521 return beforeChildParent
->addChildIgnoringContinuation(newChild
, beforeChild
);
524 void LayoutInline::paint(const PaintInfo
& paintInfo
, const LayoutPoint
& paintOffset
)
526 InlinePainter(*this).paint(paintInfo
, paintOffset
);
529 template<typename GeneratorContext
>
530 void LayoutInline::generateLineBoxRects(GeneratorContext
& yield
) const
532 if (!alwaysCreateLineBoxes()) {
533 generateCulledLineBoxRects(yield
, this);
534 } else if (InlineFlowBox
* curr
= firstLineBox()) {
535 for (; curr
; curr
= curr
->nextLineBox())
536 yield(LayoutRect(curr
->topLeft(), curr
->size()));
540 template<typename GeneratorContext
>
541 void LayoutInline::generateCulledLineBoxRects(GeneratorContext
& yield
, const LayoutInline
* container
) const
543 if (!culledInlineFirstLineBox())
546 bool isHorizontal
= style()->isHorizontalWritingMode();
548 for (LayoutObject
* curr
= firstChild(); curr
; curr
= curr
->nextSibling()) {
549 if (curr
->isFloatingOrOutOfFlowPositioned())
552 // We want to get the margin box in the inline direction, and then use our font ascent/descent in the block
553 // direction (aligned to the root box's baseline).
555 LayoutBox
* currBox
= toLayoutBox(curr
);
556 if (currBox
->inlineBoxWrapper()) {
557 RootInlineBox
& rootBox
= currBox
->inlineBoxWrapper()->root();
558 int logicalTop
= rootBox
.logicalTop() + (rootBox
.layoutObject().style(rootBox
.isFirstLineStyle())->font().fontMetrics().ascent() - container
->style(rootBox
.isFirstLineStyle())->font().fontMetrics().ascent());
559 int logicalHeight
= container
->style(rootBox
.isFirstLineStyle())->font().fontMetrics().height();
561 yield(LayoutRect(currBox
->inlineBoxWrapper()->x() - currBox
->marginLeft(), logicalTop
, currBox
->size().width() + currBox
->marginWidth(), logicalHeight
));
563 yield(LayoutRect(logicalTop
, currBox
->inlineBoxWrapper()->y() - currBox
->marginTop(), logicalHeight
, currBox
->size().height() + currBox
->marginHeight()));
565 } else if (curr
->isLayoutInline()) {
566 // If the child doesn't need line boxes either, then we can recur.
567 LayoutInline
* currInline
= toLayoutInline(curr
);
568 if (!currInline
->alwaysCreateLineBoxes()) {
569 currInline
->generateCulledLineBoxRects(yield
, container
);
571 for (InlineFlowBox
* childLine
= currInline
->firstLineBox(); childLine
; childLine
= childLine
->nextLineBox()) {
572 RootInlineBox
& rootBox
= childLine
->root();
573 int logicalTop
= rootBox
.logicalTop() + (rootBox
.layoutObject().style(rootBox
.isFirstLineStyle())->font().fontMetrics().ascent() - container
->style(rootBox
.isFirstLineStyle())->font().fontMetrics().ascent());
574 int logicalHeight
= container
->style(rootBox
.isFirstLineStyle())->font().fontMetrics().height();
576 yield(LayoutRect(childLine
->x() - childLine
->marginLogicalLeft(),
578 childLine
->logicalWidth() + childLine
->marginLogicalLeft() + childLine
->marginLogicalRight(),
581 yield(LayoutRect(logicalTop
,
582 childLine
->y() - childLine
->marginLogicalLeft(),
584 childLine
->logicalWidth() + childLine
->marginLogicalLeft() + childLine
->marginLogicalRight()));
588 } else if (curr
->isText()) {
589 LayoutText
* currText
= toLayoutText(curr
);
590 for (InlineTextBox
* childText
= currText
->firstTextBox(); childText
; childText
= childText
->nextTextBox()) {
591 RootInlineBox
& rootBox
= childText
->root();
592 int logicalTop
= rootBox
.logicalTop() + (rootBox
.layoutObject().style(rootBox
.isFirstLineStyle())->font().fontMetrics().ascent() - container
->style(rootBox
.isFirstLineStyle())->font().fontMetrics().ascent());
593 int logicalHeight
= container
->style(rootBox
.isFirstLineStyle())->font().fontMetrics().height();
595 yield(LayoutRect(childText
->x(), logicalTop
, childText
->logicalWidth(), logicalHeight
));
597 yield(LayoutRect(logicalTop
, childText
->y(), logicalHeight
, childText
->logicalWidth()));
605 class AbsoluteRectsGeneratorContext
{
607 AbsoluteRectsGeneratorContext(Vector
<IntRect
>& rects
, const LayoutPoint
& accumulatedOffset
)
609 , m_accumulatedOffset(accumulatedOffset
) { }
611 void operator()(const LayoutRect
& rect
)
613 IntRect intRect
= enclosingIntRect(rect
);
614 intRect
.move(m_accumulatedOffset
.x(), m_accumulatedOffset
.y());
615 m_rects
.append(intRect
);
618 Vector
<IntRect
>& m_rects
;
619 const LayoutPoint
& m_accumulatedOffset
;
622 } // unnamed namespace
624 void LayoutInline::absoluteRects(Vector
<IntRect
>& rects
, const LayoutPoint
& accumulatedOffset
) const
626 AbsoluteRectsGeneratorContext
context(rects
, accumulatedOffset
);
627 generateLineBoxRects(context
);
629 context(LayoutRect());
631 if (const LayoutBoxModelObject
* continuation
= this->continuation()) {
632 if (continuation
->isBox()) {
633 const LayoutBox
* box
= toLayoutBox(continuation
);
634 continuation
->absoluteRects(rects
, toLayoutPoint(accumulatedOffset
- containingBlock()->location() + box
->locationOffset()));
636 continuation
->absoluteRects(rects
, toLayoutPoint(accumulatedOffset
- containingBlock()->location()));
644 class AbsoluteQuadsGeneratorContext
{
646 AbsoluteQuadsGeneratorContext(const LayoutInline
* layoutObject
, Vector
<FloatQuad
>& quads
)
650 m_geometryMap
.pushMappingsToAncestor(layoutObject
, 0);
653 void operator()(const FloatRect
& rect
)
655 m_quads
.append(m_geometryMap
.absoluteRect(rect
));
657 void operator()(const LayoutRect
& rect
)
659 operator()(FloatRect(rect
));
662 Vector
<FloatQuad
>& m_quads
;
663 LayoutGeometryMap m_geometryMap
;
666 } // unnamed namespace
668 void LayoutInline::absoluteQuads(Vector
<FloatQuad
>& quads
, bool* wasFixed
) const
670 AbsoluteQuadsGeneratorContext
context(this, quads
);
671 generateLineBoxRects(context
);
673 context(FloatRect());
675 if (const LayoutBoxModelObject
* continuation
= this->continuation())
676 continuation
->absoluteQuads(quads
, wasFixed
);
679 LayoutUnit
LayoutInline::offsetLeft() const
682 if (InlineBox
* firstBox
= firstLineBoxIncludingCulling()) {
683 topLeft
= firstBox
->topLeft();
685 return adjustedPositionRelativeToOffsetParent(topLeft
).x();
688 LayoutUnit
LayoutInline::offsetTop() const
691 if (InlineBox
* firstBox
= firstLineBoxIncludingCulling()) {
692 topLeft
= firstBox
->topLeft();
694 return adjustedPositionRelativeToOffsetParent(topLeft
).y();
697 static LayoutUnit
computeMargin(const LayoutInline
* layoutObject
, const Length
& margin
)
699 if (margin
.isFixed())
700 return margin
.value();
701 if (margin
.hasPercent())
702 return minimumValueForLength(margin
, std::max(LayoutUnit(), layoutObject
->containingBlock()->availableLogicalWidth()));
706 LayoutRectOutsets
LayoutInline::marginBoxOutsets() const
708 return LayoutRectOutsets(marginTop(), marginRight(), marginBottom(), marginLeft());
711 LayoutUnit
LayoutInline::marginLeft() const
713 return computeMargin(this, style()->marginLeft());
716 LayoutUnit
LayoutInline::marginRight() const
718 return computeMargin(this, style()->marginRight());
721 LayoutUnit
LayoutInline::marginTop() const
723 return computeMargin(this, style()->marginTop());
726 LayoutUnit
LayoutInline::marginBottom() const
728 return computeMargin(this, style()->marginBottom());
731 LayoutUnit
LayoutInline::marginStart(const ComputedStyle
* otherStyle
) const
733 return computeMargin(this, style()->marginStartUsing(otherStyle
? otherStyle
: style()));
736 LayoutUnit
LayoutInline::marginEnd(const ComputedStyle
* otherStyle
) const
738 return computeMargin(this, style()->marginEndUsing(otherStyle
? otherStyle
: style()));
741 LayoutUnit
LayoutInline::marginBefore(const ComputedStyle
* otherStyle
) const
743 return computeMargin(this, style()->marginBeforeUsing(otherStyle
? otherStyle
: style()));
746 LayoutUnit
LayoutInline::marginAfter(const ComputedStyle
* otherStyle
) const
748 return computeMargin(this, style()->marginAfterUsing(otherStyle
? otherStyle
: style()));
751 bool LayoutInline::nodeAtPoint(HitTestResult
& result
,
752 const HitTestLocation
& locationInContainer
, const LayoutPoint
& accumulatedOffset
, HitTestAction hitTestAction
)
754 return m_lineBoxes
.hitTest(LineLayoutBoxModel(this), result
, locationInContainer
, accumulatedOffset
, hitTestAction
);
759 class HitTestCulledInlinesGeneratorContext
{
761 HitTestCulledInlinesGeneratorContext(Region
& region
, const HitTestLocation
& location
) : m_intersected(false), m_region(region
), m_location(location
) { }
762 void operator()(const FloatRect
& rect
)
764 m_intersected
= m_intersected
|| m_location
.intersects(rect
);
765 m_region
.unite(enclosingIntRect(rect
));
767 void operator()(const LayoutRect
& rect
)
769 m_intersected
= m_intersected
|| m_location
.intersects(rect
);
770 m_region
.unite(enclosingIntRect(rect
));
772 bool intersected() const { return m_intersected
; }
776 const HitTestLocation
& m_location
;
779 } // unnamed namespace
781 bool LayoutInline::hitTestCulledInline(HitTestResult
& result
, const HitTestLocation
& locationInContainer
, const LayoutPoint
& accumulatedOffset
)
783 ASSERT(!alwaysCreateLineBoxes());
784 if (!visibleToHitTestRequest(result
.hitTestRequest()))
787 HitTestLocation
tmpLocation(locationInContainer
, -toLayoutSize(accumulatedOffset
));
790 HitTestCulledInlinesGeneratorContext
context(regionResult
, tmpLocation
);
791 generateCulledLineBoxRects(context
, this);
793 if (context
.intersected()) {
794 updateHitTestResult(result
, tmpLocation
.point());
795 // We can not use addNodeToListBasedTestResult to determine if we fully enclose the hit-test area
796 // because it can only handle rectangular targets.
797 result
.addNodeToListBasedTestResult(node(), locationInContainer
);
798 return regionResult
.contains(tmpLocation
.boundingBox());
803 PositionWithAffinity
LayoutInline::positionForPoint(const LayoutPoint
& point
)
805 // FIXME: Does not deal with relative positioned inlines (should it?)
806 LayoutBlock
* cb
= containingBlock();
807 if (firstLineBoxIncludingCulling()) {
808 // This inline actually has a line box. We must have clicked in the border/padding of one of these boxes. We
809 // should try to find a result by asking our containing block.
810 return cb
->positionForPoint(point
);
813 // Translate the coords from the pre-anonymous block to the post-anonymous block.
814 LayoutPoint parentBlockPoint
= cb
->location() + point
;
815 LayoutBoxModelObject
* c
= continuation();
817 LayoutBox
* contBlock
= c
->isInline() ? c
->containingBlock() : toLayoutBlock(c
);
818 if (c
->isInline() || c
->slowFirstChild())
819 return c
->positionForPoint(parentBlockPoint
- contBlock
->locationOffset());
820 c
= toLayoutBlock(c
)->inlineElementContinuation();
823 return LayoutBoxModelObject::positionForPoint(point
);
828 class LinesBoundingBoxGeneratorContext
{
830 LinesBoundingBoxGeneratorContext(FloatRect
& rect
) : m_rect(rect
) { }
831 void operator()(const FloatRect
& rect
)
833 m_rect
.uniteIfNonZero(rect
);
835 void operator()(const LayoutRect
& rect
)
837 operator()(FloatRect(rect
));
843 } // unnamed namespace
845 IntRect
LayoutInline::linesBoundingBox() const
847 if (!alwaysCreateLineBoxes()) {
848 ASSERT(!firstLineBox());
849 FloatRect floatResult
;
850 LinesBoundingBoxGeneratorContext
context(floatResult
);
851 generateCulledLineBoxRects(context
, this);
852 return enclosingIntRect(floatResult
);
857 // See <rdar://problem/5289721>, for an unknown reason the linked list here is sometimes inconsistent, first is non-zero and last is zero. We have been
858 // unable to reproduce this at all (and consequently unable to figure ot why this is happening). The assert will hopefully catch the problem in debug
859 // builds and help us someday figure out why. We also put in a redundant check of lastLineBox() to avoid the crash for now.
860 ASSERT(!firstLineBox() == !lastLineBox()); // Either both are null or both exist.
861 if (firstLineBox() && lastLineBox()) {
862 // Return the width of the minimal left side and the maximal right side.
863 LayoutUnit logicalLeftSide
= 0;
864 LayoutUnit logicalRightSide
= 0;
865 for (InlineFlowBox
* curr
= firstLineBox(); curr
; curr
= curr
->nextLineBox()) {
866 if (curr
== firstLineBox() || curr
->logicalLeft() < logicalLeftSide
)
867 logicalLeftSide
= curr
->logicalLeft();
868 if (curr
== firstLineBox() || curr
->logicalRight() > logicalRightSide
)
869 logicalRightSide
= curr
->logicalRight();
872 bool isHorizontal
= style()->isHorizontalWritingMode();
874 LayoutUnit x
= isHorizontal
? logicalLeftSide
: firstLineBox()->x();
875 LayoutUnit y
= isHorizontal
? firstLineBox()->y() : logicalLeftSide
;
876 LayoutUnit width
= isHorizontal
? logicalRightSide
- logicalLeftSide
: lastLineBox()->logicalBottom() - x
;
877 LayoutUnit height
= isHorizontal
? lastLineBox()->logicalBottom() - y
: logicalRightSide
- logicalLeftSide
;
878 result
= enclosingIntRect(LayoutRect(x
, y
, width
, height
));
884 InlineBox
* LayoutInline::culledInlineFirstLineBox() const
886 for (LayoutObject
* curr
= firstChild(); curr
; curr
= curr
->nextSibling()) {
887 if (curr
->isFloatingOrOutOfFlowPositioned())
890 // We want to get the margin box in the inline direction, and then use our font ascent/descent in the block
891 // direction (aligned to the root box's baseline).
893 return toLayoutBox(curr
)->inlineBoxWrapper();
894 if (curr
->isLayoutInline()) {
895 LayoutInline
* currInline
= toLayoutInline(curr
);
896 InlineBox
* result
= currInline
->firstLineBoxIncludingCulling();
899 } else if (curr
->isText()) {
900 LayoutText
* currText
= toLayoutText(curr
);
901 if (currText
->firstTextBox())
902 return currText
->firstTextBox();
908 InlineBox
* LayoutInline::culledInlineLastLineBox() const
910 for (LayoutObject
* curr
= lastChild(); curr
; curr
= curr
->previousSibling()) {
911 if (curr
->isFloatingOrOutOfFlowPositioned())
914 // We want to get the margin box in the inline direction, and then use our font ascent/descent in the block
915 // direction (aligned to the root box's baseline).
917 return toLayoutBox(curr
)->inlineBoxWrapper();
918 if (curr
->isLayoutInline()) {
919 LayoutInline
* currInline
= toLayoutInline(curr
);
920 InlineBox
* result
= currInline
->lastLineBoxIncludingCulling();
923 } else if (curr
->isText()) {
924 LayoutText
* currText
= toLayoutText(curr
);
925 if (currText
->lastTextBox())
926 return currText
->lastTextBox();
932 LayoutRect
LayoutInline::culledInlineVisualOverflowBoundingBox() const
934 FloatRect floatResult
;
935 LinesBoundingBoxGeneratorContext
context(floatResult
);
936 generateCulledLineBoxRects(context
, this);
937 LayoutRect
result(enclosingLayoutRect(floatResult
));
938 bool isHorizontal
= style()->isHorizontalWritingMode();
939 for (LayoutObject
* curr
= firstChild(); curr
; curr
= curr
->nextSibling()) {
940 if (curr
->isFloatingOrOutOfFlowPositioned())
943 // For overflow we just have to propagate by hand and recompute it all.
945 LayoutBox
* currBox
= toLayoutBox(curr
);
946 if (!currBox
->hasSelfPaintingLayer() && currBox
->inlineBoxWrapper()) {
947 LayoutRect logicalRect
= currBox
->logicalVisualOverflowRectForPropagation(styleRef());
949 logicalRect
.moveBy(currBox
->location());
950 result
.uniteIfNonZero(logicalRect
);
952 logicalRect
.moveBy(currBox
->location());
953 result
.uniteIfNonZero(logicalRect
.transposedRect());
956 } else if (curr
->isLayoutInline()) {
957 // If the child doesn't need line boxes either, then we can recur.
958 LayoutInline
* currInline
= toLayoutInline(curr
);
959 if (!currInline
->alwaysCreateLineBoxes())
960 result
.uniteIfNonZero(currInline
->culledInlineVisualOverflowBoundingBox());
961 else if (!currInline
->hasSelfPaintingLayer())
962 result
.uniteIfNonZero(currInline
->visualOverflowRect());
963 } else if (curr
->isText()) {
964 LayoutText
* currText
= toLayoutText(curr
);
965 result
.uniteIfNonZero(currText
->visualOverflowRect());
971 LayoutRect
LayoutInline::linesVisualOverflowBoundingBox() const
973 if (!alwaysCreateLineBoxes())
974 return culledInlineVisualOverflowBoundingBox();
976 if (!firstLineBox() || !lastLineBox())
979 // Return the width of the minimal left side and the maximal right side.
980 LayoutUnit logicalLeftSide
= LayoutUnit::max();
981 LayoutUnit logicalRightSide
= LayoutUnit::min();
982 for (InlineFlowBox
* curr
= firstLineBox(); curr
; curr
= curr
->nextLineBox()) {
983 logicalLeftSide
= std::min(logicalLeftSide
, curr
->logicalLeftVisualOverflow());
984 logicalRightSide
= std::max(logicalRightSide
, curr
->logicalRightVisualOverflow());
987 RootInlineBox
& firstRootBox
= firstLineBox()->root();
988 RootInlineBox
& lastRootBox
= lastLineBox()->root();
990 LayoutUnit logicalTop
= firstLineBox()->logicalTopVisualOverflow(firstRootBox
.lineTop());
991 LayoutUnit logicalWidth
= logicalRightSide
- logicalLeftSide
;
992 LayoutUnit logicalHeight
= lastLineBox()->logicalBottomVisualOverflow(lastRootBox
.lineBottom()) - logicalTop
;
994 LayoutRect
rect(logicalLeftSide
, logicalTop
, logicalWidth
, logicalHeight
);
995 if (!style()->isHorizontalWritingMode())
996 rect
= rect
.transposedRect();
1000 LayoutRect
LayoutInline::absoluteClippedOverflowRect() const
1002 if (!continuation())
1003 return clippedOverflowRect(view());
1005 FloatRect floatResult
;
1006 LinesBoundingBoxGeneratorContext
context(floatResult
);
1008 LayoutInline
* endContinuation
= inlineElementContinuation();
1009 while (LayoutInline
* nextContinuation
= endContinuation
->inlineElementContinuation())
1010 endContinuation
= nextContinuation
;
1012 for (LayoutBlock
* currBlock
= containingBlock(); currBlock
&& currBlock
->isAnonymousBlock(); currBlock
= toLayoutBlock(currBlock
->nextSibling())) {
1013 for (LayoutObject
* curr
= currBlock
->firstChild(); curr
; curr
= curr
->nextSibling()) {
1014 LayoutRect
rect(curr
->clippedOverflowRectForPaintInvalidation(view()));
1015 context(FloatRect(rect
));
1016 if (curr
== endContinuation
)
1017 return LayoutRect(enclosingIntRect(floatResult
));
1020 return LayoutRect();
1023 LayoutRect
LayoutInline::clippedOverflowRectForPaintInvalidation(const LayoutBoxModelObject
* paintInvalidationContainer
, const PaintInvalidationState
* paintInvalidationState
) const
1025 // If we don't create line boxes, we don't have any invalidations to do.
1026 if (!alwaysCreateLineBoxes())
1027 return LayoutRect();
1028 return clippedOverflowRect(paintInvalidationContainer
);
1031 LayoutRect
LayoutInline::clippedOverflowRect(const LayoutBoxModelObject
* paintInvalidationContainer
, const PaintInvalidationState
* paintInvalidationState
) const
1033 if (style()->visibility() != VISIBLE
)
1034 return LayoutRect();
1036 LayoutRect
overflowRect(visualOverflowRect());
1037 if (overflowRect
.isEmpty())
1038 return overflowRect
;
1040 mapRectToPaintInvalidationBacking(paintInvalidationContainer
, overflowRect
, paintInvalidationState
);
1041 return overflowRect
;
1044 LayoutRect
LayoutInline::visualOverflowRect() const
1046 LayoutRect overflowRect
= linesVisualOverflowBoundingBox();
1047 LayoutUnit outlineOutset
= style()->outlineOutsetExtent();
1048 if (outlineOutset
) {
1049 Vector
<LayoutRect
> rects
;
1050 // We have already included outline extents of line boxes in linesVisualOverflowBoundingBox(),
1051 // so the following just add outline rects for children and continuations.
1052 addOutlineRectsForChildrenAndContinuations(rects
, LayoutPoint(), outlineRectsShouldIncludeBlockVisualOverflow());
1053 if (!rects
.isEmpty()) {
1054 LayoutRect outlineRect
= unionRectEvenIfEmpty(rects
);
1055 outlineRect
.inflate(outlineOutset
);
1056 overflowRect
.unite(outlineRect
);
1059 return overflowRect
;
1062 void LayoutInline::mapRectToPaintInvalidationBacking(const LayoutBoxModelObject
* paintInvalidationContainer
, LayoutRect
& rect
, const PaintInvalidationState
* paintInvalidationState
) const
1064 if (paintInvalidationState
&& paintInvalidationState
->canMapToContainer(paintInvalidationContainer
)) {
1065 if (style()->hasInFlowPosition() && layer())
1066 rect
.move(layer()->offsetForInFlowPosition());
1067 rect
.move(paintInvalidationState
->paintOffset());
1068 if (paintInvalidationState
->isClipped())
1069 rect
.intersect(paintInvalidationState
->clipRect());
1073 if (paintInvalidationContainer
== this)
1076 bool containerSkipped
;
1077 LayoutObject
* o
= container(paintInvalidationContainer
, &containerSkipped
);
1081 LayoutPoint topLeft
= rect
.location();
1083 if (style()->hasInFlowPosition() && layer()) {
1084 // Apply the in-flow position offset when invalidating a rectangle. The layer
1085 // is translated, but the layout box isn't, so we need to do this to get the
1086 // right dirty rect. Since this is called from LayoutObject::setStyle, the relative position
1087 // flag on the LayoutObject has been cleared, so use the one on the style().
1088 topLeft
+= layer()->offsetForInFlowPosition();
1091 // FIXME: We ignore the lightweight clipping rect that controls use, since if |o| is in mid-layout,
1092 // its controlClipRect will be wrong. For overflow clip we use the values cached by the layer.
1093 rect
.setLocation(topLeft
);
1094 if (o
->hasOverflowClip()) {
1095 LayoutBox
* containerBox
= toLayoutBox(o
);
1096 containerBox
->applyCachedClipAndScrollOffsetForPaintInvalidation(rect
);
1101 if (containerSkipped
) {
1102 // If the paintInvalidationContainer is below o, then we need to map the rect into paintInvalidationContainer's coordinates.
1103 LayoutSize containerOffset
= paintInvalidationContainer
->offsetFromAncestorContainer(o
);
1104 rect
.move(-containerOffset
);
1108 o
->mapRectToPaintInvalidationBacking(paintInvalidationContainer
, rect
, paintInvalidationState
);
1111 LayoutSize
LayoutInline::offsetFromContainer(const LayoutObject
* container
, const LayoutPoint
& point
, bool* offsetDependsOnPoint
) const
1113 ASSERT(container
== this->container());
1116 if (isInFlowPositioned())
1117 offset
+= offsetForInFlowPosition();
1119 offset
+= container
->columnOffset(point
);
1121 if (container
->hasOverflowClip())
1122 offset
-= toLayoutBox(container
)->scrolledContentOffset();
1124 if (offsetDependsOnPoint
)
1125 *offsetDependsOnPoint
= (container
->isBox() && container
->style()->isFlippedBlocksWritingMode()) || container
->isLayoutFlowThread();
1130 void LayoutInline::mapLocalToContainer(const LayoutBoxModelObject
* paintInvalidationContainer
, TransformState
& transformState
, MapCoordinatesFlags mode
, bool* wasFixed
, const PaintInvalidationState
* paintInvalidationState
) const
1132 if (paintInvalidationContainer
== this)
1135 if (paintInvalidationState
&& paintInvalidationState
->canMapToContainer(paintInvalidationContainer
)) {
1136 LayoutSize offset
= paintInvalidationState
->paintOffset();
1137 if (style()->hasInFlowPosition() && layer())
1138 offset
+= layer()->offsetForInFlowPosition();
1139 transformState
.move(offset
);
1143 bool containerSkipped
;
1144 LayoutObject
* o
= container(paintInvalidationContainer
, &containerSkipped
);
1148 if (mode
& ApplyContainerFlip
&& o
->isBox()) {
1149 if (o
->style()->isFlippedBlocksWritingMode()) {
1150 IntPoint centerPoint
= roundedIntPoint(transformState
.mappedPoint());
1151 transformState
.move(toLayoutBox(o
)->flipForWritingMode(LayoutPoint(centerPoint
)) - centerPoint
);
1153 mode
&= ~ApplyContainerFlip
;
1156 LayoutSize containerOffset
= offsetFromContainer(o
, roundedLayoutPoint(transformState
.mappedPoint()));
1158 bool preserve3D
= mode
& UseTransforms
&& (o
->style()->preserves3D() || style()->preserves3D());
1159 if (mode
& UseTransforms
&& shouldUseTransformFromContainer(o
)) {
1160 TransformationMatrix t
;
1161 getTransformFromContainer(o
, containerOffset
, t
);
1162 transformState
.applyTransform(t
, preserve3D
? TransformState::AccumulateTransform
: TransformState::FlattenTransform
);
1164 transformState
.move(containerOffset
.width(), containerOffset
.height(), preserve3D
? TransformState::AccumulateTransform
: TransformState::FlattenTransform
);
1167 if (containerSkipped
) {
1168 // There can't be a transform between paintInvalidationContainer and o, because transforms create containers, so it should be safe
1169 // to just subtract the delta between the paintInvalidationContainer and o.
1170 LayoutSize containerOffset
= paintInvalidationContainer
->offsetFromAncestorContainer(o
);
1171 transformState
.move(-containerOffset
.width(), -containerOffset
.height(), preserve3D
? TransformState::AccumulateTransform
: TransformState::FlattenTransform
);
1175 o
->mapLocalToContainer(paintInvalidationContainer
, transformState
, mode
, wasFixed
, paintInvalidationState
);
1178 void LayoutInline::updateDragState(bool dragOn
)
1180 LayoutBoxModelObject::updateDragState(dragOn
);
1181 if (LayoutBoxModelObject
* continuation
= this->continuation())
1182 continuation
->updateDragState(dragOn
);
1185 void LayoutInline::childBecameNonInline(LayoutObject
* child
)
1187 // We have to split the parent flow.
1188 LayoutBlock
* newBox
= containingBlock()->createAnonymousBlock();
1189 LayoutBoxModelObject
* oldContinuation
= continuation();
1190 setContinuation(newBox
);
1191 LayoutObject
* beforeChild
= child
->nextSibling();
1192 children()->removeChildNode(this, child
);
1193 splitFlow(beforeChild
, newBox
, child
, oldContinuation
);
1196 void LayoutInline::updateHitTestResult(HitTestResult
& result
, const LayoutPoint
& point
)
1198 if (result
.innerNode())
1202 LayoutPoint
localPoint(point
);
1204 if (isInlineElementContinuation()) {
1205 // We're in the continuation of a split inline. Adjust our local point to be in the coordinate space
1206 // of the principal layoutObject's containing block. This will end up being the innerNode.
1207 LayoutBlock
* firstBlock
= n
->layoutObject()->containingBlock();
1209 // Get our containing block.
1210 LayoutBox
* block
= containingBlock();
1211 localPoint
.moveBy(block
->location() - firstBlock
->locationOffset());
1214 result
.setNodeAndPosition(n
, localPoint
);
1218 void LayoutInline::dirtyLineBoxes(bool fullLayout
)
1221 m_lineBoxes
.deleteLineBoxes();
1225 if (!alwaysCreateLineBoxes()) {
1226 // We have to grovel into our children in order to dirty the appropriate lines.
1227 for (LayoutObject
* curr
= firstChild(); curr
; curr
= curr
->nextSibling()) {
1228 if (curr
->isFloatingOrOutOfFlowPositioned())
1230 if (curr
->isBox() && !curr
->needsLayout()) {
1231 LayoutBox
* currBox
= toLayoutBox(curr
);
1232 if (currBox
->inlineBoxWrapper())
1233 currBox
->inlineBoxWrapper()->root().markDirty();
1234 } else if (!curr
->selfNeedsLayout()) {
1235 if (curr
->isLayoutInline()) {
1236 LayoutInline
* currInline
= toLayoutInline(curr
);
1237 for (InlineFlowBox
* childLine
= currInline
->firstLineBox(); childLine
; childLine
= childLine
->nextLineBox())
1238 childLine
->root().markDirty();
1239 } else if (curr
->isText()) {
1240 LayoutText
* currText
= toLayoutText(curr
);
1241 for (InlineTextBox
* childText
= currText
->firstTextBox(); childText
; childText
= childText
->nextTextBox())
1242 childText
->root().markDirty();
1247 m_lineBoxes
.dirtyLineBoxes();
1251 InlineFlowBox
* LayoutInline::createInlineFlowBox()
1253 return new InlineFlowBox(*this);
1256 InlineFlowBox
* LayoutInline::createAndAppendInlineFlowBox()
1258 setAlwaysCreateLineBoxes();
1259 InlineFlowBox
* flowBox
= createInlineFlowBox();
1260 m_lineBoxes
.appendLineBox(flowBox
);
1264 LayoutUnit
LayoutInline::lineHeight(bool firstLine
, LineDirectionMode
/*direction*/, LinePositionMode
/*linePositionMode*/) const
1266 if (firstLine
&& document().styleEngine().usesFirstLineRules()) {
1267 const ComputedStyle
* s
= style(firstLine
);
1269 return s
->computedLineHeight();
1272 return style()->computedLineHeight();
1275 int LayoutInline::baselinePosition(FontBaseline baselineType
, bool firstLine
, LineDirectionMode direction
, LinePositionMode linePositionMode
) const
1277 ASSERT(linePositionMode
== PositionOnContainingLine
);
1278 const FontMetrics
& fontMetrics
= style(firstLine
)->fontMetrics();
1279 return fontMetrics
.ascent(baselineType
) + (lineHeight(firstLine
, direction
, linePositionMode
) - fontMetrics
.height()) / 2;
1282 LayoutSize
LayoutInline::offsetForInFlowPositionedInline(const LayoutBox
& child
) const
1284 // FIXME: This function isn't right with mixed writing modes.
1286 ASSERT(isInFlowPositioned());
1287 if (!isInFlowPositioned())
1288 return LayoutSize();
1290 // When we have an enclosing relpositioned inline, we need to add in the offset of the first line
1291 // box from the rest of the content, but only in the cases where we know we're positioned
1292 // relative to the inline itself.
1294 LayoutSize logicalOffset
;
1295 LayoutUnit inlinePosition
;
1296 LayoutUnit blockPosition
;
1297 if (firstLineBox()) {
1298 inlinePosition
= firstLineBox()->logicalLeft();
1299 blockPosition
= firstLineBox()->logicalTop();
1301 inlinePosition
= layer()->staticInlinePosition();
1302 blockPosition
= layer()->staticBlockPosition();
1305 // Per http://www.w3.org/TR/CSS2/visudet.html#abs-non-replaced-width an absolute positioned box
1306 // with a static position should locate itself as though it is a normal flow box in relation to
1307 // its containing block. If this relative-positioned inline has a negative offset we need to
1308 // compensate for it so that we align the positioned object with the edge of its containing block.
1309 if (child
.style()->hasStaticInlinePosition(style()->isHorizontalWritingMode()))
1310 logicalOffset
.setWidth(std::max(LayoutUnit(), -offsetForInFlowPosition().width()));
1312 logicalOffset
.setWidth(inlinePosition
);
1314 if (!child
.style()->hasStaticBlockPosition(style()->isHorizontalWritingMode()))
1315 logicalOffset
.setHeight(blockPosition
);
1317 return style()->isHorizontalWritingMode() ? logicalOffset
: logicalOffset
.transposedSize();
1320 void LayoutInline::imageChanged(WrappedImagePtr
, const IntRect
*)
1325 // FIXME: We can do better.
1326 setShouldDoFullPaintInvalidation();
1331 class AbsoluteLayoutRectsGeneratorContext
{
1333 AbsoluteLayoutRectsGeneratorContext(Vector
<LayoutRect
>& rects
, const LayoutPoint
& accumulatedOffset
)
1335 , m_accumulatedOffset(accumulatedOffset
) { }
1337 void operator()(const FloatRect
& rect
)
1339 operator()(LayoutRect(rect
));
1341 void operator()(const LayoutRect
& rect
)
1343 LayoutRect
layoutRect(rect
);
1344 layoutRect
.moveBy(m_accumulatedOffset
);
1345 m_rects
.append(layoutRect
);
1348 Vector
<LayoutRect
>& m_rects
;
1349 const LayoutPoint
& m_accumulatedOffset
;
1352 } // unnamed namespace
1354 void LayoutInline::addOutlineRects(Vector
<LayoutRect
>& rects
, const LayoutPoint
& additionalOffset
, IncludeBlockVisualOverflowOrNot includeBlockOverflows
) const
1356 AbsoluteLayoutRectsGeneratorContext
context(rects
, additionalOffset
);
1357 generateLineBoxRects(context
);
1358 addOutlineRectsForChildrenAndContinuations(rects
, additionalOffset
, includeBlockOverflows
);
1361 void LayoutInline::addOutlineRectsForChildrenAndContinuations(Vector
<LayoutRect
>& rects
, const LayoutPoint
& additionalOffset
, IncludeBlockVisualOverflowOrNot includeBlockOverflows
) const
1363 addOutlineRectsForNormalChildren(rects
, additionalOffset
, includeBlockOverflows
);
1364 addOutlineRectsForContinuations(rects
, additionalOffset
, includeBlockOverflows
);
1367 void LayoutInline::addOutlineRectsForContinuations(Vector
<LayoutRect
>& rects
, const LayoutPoint
& additionalOffset
, IncludeBlockVisualOverflowOrNot includeBlockOverflows
) const
1369 if (LayoutBoxModelObject
* continuation
= this->continuation()) {
1370 if (continuation
->isInline())
1371 continuation
->addOutlineRects(rects
, additionalOffset
+ (continuation
->containingBlock()->location() - containingBlock()->location()), includeBlockOverflows
);
1373 continuation
->addOutlineRects(rects
, additionalOffset
+ (toLayoutBox(continuation
)->location() - containingBlock()->location()), includeBlockOverflows
);
1377 void LayoutInline::computeSelfHitTestRects(Vector
<LayoutRect
>& rects
, const LayoutPoint
& layerOffset
) const
1379 AbsoluteLayoutRectsGeneratorContext
context(rects
, layerOffset
);
1380 generateLineBoxRects(context
);
1383 void LayoutInline::addAnnotatedRegions(Vector
<AnnotatedRegionValue
>& regions
)
1385 // Convert the style regions to absolute coordinates.
1386 if (style()->visibility() != VISIBLE
)
1389 if (style()->getDraggableRegionMode() == DraggableRegionNone
)
1392 AnnotatedRegionValue region
;
1393 region
.draggable
= style()->getDraggableRegionMode() == DraggableRegionDrag
;
1394 region
.bounds
= LayoutRect(linesBoundingBox());
1396 LayoutObject
* container
= containingBlock();
1400 FloatPoint absPos
= container
->localToAbsolute();
1401 region
.bounds
.setX(absPos
.x() + region
.bounds
.x());
1402 region
.bounds
.setY(absPos
.y() + region
.bounds
.y());
1404 regions
.append(region
);
1407 void LayoutInline::invalidateDisplayItemClients(const LayoutBoxModelObject
& paintInvalidationContainer
) const
1409 LayoutBoxModelObject::invalidateDisplayItemClients(paintInvalidationContainer
);
1410 for (InlineFlowBox
* box
= firstLineBox(); box
; box
= box
->nextLineBox())
1411 paintInvalidationContainer
.invalidateDisplayItemClientOnBacking(*box
);
1414 } // namespace blink