Move parseFontFaceDescriptor to CSSPropertyParser.cpp
[chromium-blink-merge.git] / third_party / WebKit / Source / core / layout / LayoutInline.cpp
blob2cb7fca42b1801042c5509bb758ee0c9865bb3ce
1 /*
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.
23 #include "config.h"
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"
46 namespace blink {
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);
66 return layoutObject;
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();
79 if (continuation) {
80 continuation->destroy();
81 setContinuation(nullptr);
84 if (!documentBeingDestroyed()) {
85 if (firstLineBox()) {
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())
100 box->remove();
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.
125 setInline(true);
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())
136 return p;
137 p = p->parent();
139 return nullptr;
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())
146 continue;
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()))
151 continue;
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())
205 return;
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) {
227 if (!fullLayout)
228 dirtyLineBoxes(false);
229 setAlwaysCreateLineBoxes();
233 LayoutRect LayoutInline::localCaretRect(InlineBox* inlineBox, int, LayoutUnit* extraWidthToEndOfLine)
235 if (firstChild()) {
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.
241 return LayoutRect();
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());
257 return caretRect;
260 void LayoutInline::addChild(LayoutObject* newChild, LayoutObject* beforeChild)
262 if (continuation())
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)
277 return this;
279 LayoutBoxModelObject* curr = nextContinuation(this);
280 LayoutBoxModelObject* nextToLast = this;
281 LayoutBoxModelObject* last = this;
282 while (curr) {
283 if (beforeChild && beforeChild->parent() == curr) {
284 if (curr->slowFirstChild() == beforeChild)
285 return last;
286 return curr;
289 nextToLast = last;
290 last = curr;
291 curr = nextContinuation(curr);
294 if (!beforeChild && !last->slowFirstChild())
295 return nextToLast;
296 return last;
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);
323 return;
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());
336 return cloneInline;
339 void LayoutInline::moveChildrenToIgnoringContinuation(LayoutInline* to, LayoutObject* startChild)
341 LayoutObject* child = startChild;
342 while (child) {
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.
442 pre = block;
443 pre->removePositionedObjects(nullptr);
444 if (pre->isLayoutBlockFlow())
445 toLayoutBlockFlow(pre)->removeFloatingObjects();
446 block = block->containingBlock();
447 } else {
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;
464 while (o) {
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;
493 if (beforeChild) {
494 beforeChildParent = toLayoutBoxModelObject(beforeChild->parent());
495 } else {
496 LayoutBoxModelObject* cont = nextContinuation(flow);
497 if (cont)
498 beforeChildParent = cont;
499 else
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())
544 return;
546 bool isHorizontal = style()->isHorizontalWritingMode();
548 for (LayoutObject* curr = firstChild(); curr; curr = curr->nextSibling()) {
549 if (curr->isFloatingOrOutOfFlowPositioned())
550 continue;
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).
554 if (curr->isBox()) {
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();
560 if (isHorizontal)
561 yield(LayoutRect(currBox->inlineBoxWrapper()->x() - currBox->marginLeft(), logicalTop, currBox->size().width() + currBox->marginWidth(), logicalHeight));
562 else
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);
570 } else {
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();
575 if (isHorizontal) {
576 yield(LayoutRect(childLine->x() - childLine->marginLogicalLeft(),
577 logicalTop,
578 childLine->logicalWidth() + childLine->marginLogicalLeft() + childLine->marginLogicalRight(),
579 logicalHeight));
580 } else {
581 yield(LayoutRect(logicalTop,
582 childLine->y() - childLine->marginLogicalLeft(),
583 logicalHeight,
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();
594 if (isHorizontal)
595 yield(LayoutRect(childText->x(), logicalTop, childText->logicalWidth(), logicalHeight));
596 else
597 yield(LayoutRect(logicalTop, childText->y(), logicalHeight, childText->logicalWidth()));
603 namespace {
605 class AbsoluteRectsGeneratorContext {
606 public:
607 AbsoluteRectsGeneratorContext(Vector<IntRect>& rects, const LayoutPoint& accumulatedOffset)
608 : m_rects(rects)
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);
617 private:
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);
628 if (rects.isEmpty())
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()));
635 } else {
636 continuation->absoluteRects(rects, toLayoutPoint(accumulatedOffset - containingBlock()->location()));
642 namespace {
644 class AbsoluteQuadsGeneratorContext {
645 public:
646 AbsoluteQuadsGeneratorContext(const LayoutInline* layoutObject, Vector<FloatQuad>& quads)
647 : m_quads(quads)
648 , m_geometryMap()
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));
661 private:
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);
672 if (quads.isEmpty())
673 context(FloatRect());
675 if (const LayoutBoxModelObject* continuation = this->continuation())
676 continuation->absoluteQuads(quads, wasFixed);
679 LayoutUnit LayoutInline::offsetLeft() const
681 LayoutPoint topLeft;
682 if (InlineBox* firstBox = firstLineBoxIncludingCulling()) {
683 topLeft = firstBox->topLeft();
685 return adjustedPositionRelativeToOffsetParent(topLeft).x();
688 LayoutUnit LayoutInline::offsetTop() const
690 LayoutPoint topLeft;
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()));
703 return LayoutUnit();
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);
757 namespace {
759 class HitTestCulledInlinesGeneratorContext {
760 public:
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; }
773 private:
774 bool m_intersected;
775 Region& m_region;
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()))
785 return false;
787 HitTestLocation tmpLocation(locationInContainer, -toLayoutSize(accumulatedOffset));
789 Region regionResult;
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());
800 return false;
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();
816 while (c) {
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);
826 namespace {
828 class LinesBoundingBoxGeneratorContext {
829 public:
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));
839 private:
840 FloatRect& m_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);
855 IntRect result;
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));
881 return result;
884 InlineBox* LayoutInline::culledInlineFirstLineBox() const
886 for (LayoutObject* curr = firstChild(); curr; curr = curr->nextSibling()) {
887 if (curr->isFloatingOrOutOfFlowPositioned())
888 continue;
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).
892 if (curr->isBox())
893 return toLayoutBox(curr)->inlineBoxWrapper();
894 if (curr->isLayoutInline()) {
895 LayoutInline* currInline = toLayoutInline(curr);
896 InlineBox* result = currInline->firstLineBoxIncludingCulling();
897 if (result)
898 return result;
899 } else if (curr->isText()) {
900 LayoutText* currText = toLayoutText(curr);
901 if (currText->firstTextBox())
902 return currText->firstTextBox();
905 return nullptr;
908 InlineBox* LayoutInline::culledInlineLastLineBox() const
910 for (LayoutObject* curr = lastChild(); curr; curr = curr->previousSibling()) {
911 if (curr->isFloatingOrOutOfFlowPositioned())
912 continue;
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).
916 if (curr->isBox())
917 return toLayoutBox(curr)->inlineBoxWrapper();
918 if (curr->isLayoutInline()) {
919 LayoutInline* currInline = toLayoutInline(curr);
920 InlineBox* result = currInline->lastLineBoxIncludingCulling();
921 if (result)
922 return result;
923 } else if (curr->isText()) {
924 LayoutText* currText = toLayoutText(curr);
925 if (currText->lastTextBox())
926 return currText->lastTextBox();
929 return nullptr;
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())
941 continue;
943 // For overflow we just have to propagate by hand and recompute it all.
944 if (curr->isBox()) {
945 LayoutBox* currBox = toLayoutBox(curr);
946 if (!currBox->hasSelfPaintingLayer() && currBox->inlineBoxWrapper()) {
947 LayoutRect logicalRect = currBox->logicalVisualOverflowRectForPropagation(styleRef());
948 if (isHorizontal) {
949 logicalRect.moveBy(currBox->location());
950 result.uniteIfNonZero(logicalRect);
951 } else {
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());
968 return result;
971 LayoutRect LayoutInline::linesVisualOverflowBoundingBox() const
973 if (!alwaysCreateLineBoxes())
974 return culledInlineVisualOverflowBoundingBox();
976 if (!firstLineBox() || !lastLineBox())
977 return LayoutRect();
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();
997 return rect;
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());
1070 return;
1073 if (paintInvalidationContainer == this)
1074 return;
1076 bool containerSkipped;
1077 LayoutObject* o = container(paintInvalidationContainer, &containerSkipped);
1078 if (!o)
1079 return;
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);
1097 if (rect.isEmpty())
1098 return;
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);
1105 return;
1108 o->mapRectToPaintInvalidationBacking(paintInvalidationContainer, rect, paintInvalidationState);
1111 LayoutSize LayoutInline::offsetFromContainer(const LayoutObject* container, const LayoutPoint& point, bool* offsetDependsOnPoint) const
1113 ASSERT(container == this->container());
1115 LayoutSize offset;
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();
1127 return offset;
1130 void LayoutInline::mapLocalToContainer(const LayoutBoxModelObject* paintInvalidationContainer, TransformState& transformState, MapCoordinatesFlags mode, bool* wasFixed, const PaintInvalidationState* paintInvalidationState) const
1132 if (paintInvalidationContainer == this)
1133 return;
1135 if (paintInvalidationState && paintInvalidationState->canMapToContainer(paintInvalidationContainer)) {
1136 LayoutSize offset = paintInvalidationState->paintOffset();
1137 if (style()->hasInFlowPosition() && layer())
1138 offset += layer()->offsetForInFlowPosition();
1139 transformState.move(offset);
1140 return;
1143 bool containerSkipped;
1144 LayoutObject* o = container(paintInvalidationContainer, &containerSkipped);
1145 if (!o)
1146 return;
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);
1163 } else {
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);
1172 return;
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())
1199 return;
1201 Node* n = node();
1202 LayoutPoint localPoint(point);
1203 if (n) {
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)
1220 if (fullLayout) {
1221 m_lineBoxes.deleteLineBoxes();
1222 return;
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())
1229 continue;
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();
1246 } else {
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);
1261 return flowBox;
1264 LayoutUnit LayoutInline::lineHeight(bool firstLine, LineDirectionMode /*direction*/, LinePositionMode /*linePositionMode*/) const
1266 if (firstLine && document().styleEngine().usesFirstLineRules()) {
1267 const ComputedStyle* s = style(firstLine);
1268 if (s != style())
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();
1300 } else {
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()));
1311 else
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*)
1322 if (!parent())
1323 return;
1325 // FIXME: We can do better.
1326 setShouldDoFullPaintInvalidation();
1329 namespace {
1331 class AbsoluteLayoutRectsGeneratorContext {
1332 public:
1333 AbsoluteLayoutRectsGeneratorContext(Vector<LayoutRect>& rects, const LayoutPoint& accumulatedOffset)
1334 : m_rects(rects)
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);
1347 private:
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);
1372 else
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)
1387 return;
1389 if (style()->getDraggableRegionMode() == DraggableRegionNone)
1390 return;
1392 AnnotatedRegionValue region;
1393 region.draggable = style()->getDraggableRegionMode() == DraggableRegionDrag;
1394 region.bounds = LayoutRect(linesBoundingBox());
1396 LayoutObject* container = containingBlock();
1397 if (!container)
1398 container = this;
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