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 "RenderInline.h"
27 #include "FloatQuad.h"
28 #include "GraphicsContext.h"
29 #include "HitTestResult.h"
30 #include "InlineTextBox.h"
32 #include "RenderArena.h"
33 #include "RenderBlock.h"
34 #include "RenderLayer.h"
35 #include "RenderTheme.h"
36 #include "RenderView.h"
37 #include "TransformState.h"
38 #include "VisiblePosition.h"
40 #if ENABLE(DASHBOARD_SUPPORT)
48 RenderInline::RenderInline(Node* node)
49 : RenderBoxModelObject(node)
50 , m_alwaysCreateLineBoxes(false)
52 setChildrenInline(true);
55 void RenderInline::willBeDestroyed()
58 // Make sure we do not retain "this" in the continuation outline table map of our containing blocks.
59 if (parent() && style()->visibility() == VISIBLE && hasOutline()) {
60 bool containingBlockPaintsContinuationOutline = continuation() || isInlineElementContinuation();
61 if (containingBlockPaintsContinuationOutline) {
62 if (RenderBlock* cb = containingBlock()) {
63 if (RenderBlock* cbCb = cb->containingBlock())
64 ASSERT(!cbCb->paintsContinuationOutline(this));
70 // Make sure to destroy anonymous children first while they are still connected to the rest of the tree, so that they will
71 // properly dirty line boxes that they are removed from. Effects that do :before/:after only on hover could crash otherwise.
72 children()->destroyLeftoverChildren();
74 // Destroy our continuation before anything other than anonymous children.
75 // The reason we don't destroy it before anonymous children is that they may
76 // have continuations of their own that are anonymous children of our continuation.
77 RenderBoxModelObject* continuation = this->continuation();
79 continuation->destroy();
83 if (!documentBeingDestroyed()) {
85 // We can't wait for RenderBoxModelObject::destroy to clear the selection,
86 // because by then we will have nuked the line boxes.
87 // FIXME: The FrameSelection should be responsible for this when it
88 // is notified of DOM mutations.
89 if (isSelectionBorder())
90 view()->clearSelection();
92 // If line boxes are contained inside a root, that means we're an inline.
93 // In that case, we need to remove all the line boxes so that the parent
94 // lines aren't pointing to deleted children. If the first line box does
95 // not have a parent that means they are either already disconnected or
96 // root lines that can just be destroyed without disconnecting.
97 if (firstLineBox()->parent()) {
98 for (InlineFlowBox* box = firstLineBox(); box; box = box->nextLineBox())
102 parent()->dirtyLinesFromChangedChild(this);
105 m_lineBoxes.deleteLineBoxes(renderArena());
107 RenderBoxModelObject::willBeDestroyed();
110 RenderInline* RenderInline::inlineElementContinuation() const
112 RenderBoxModelObject* continuation = this->continuation();
113 if (!continuation || continuation->isInline())
114 return toRenderInline(continuation);
115 return toRenderBlock(continuation)->inlineElementContinuation();
118 void RenderInline::updateBoxModelInfoFromStyle()
120 RenderBoxModelObject::updateBoxModelInfoFromStyle();
122 setInline(true); // Needed for run-ins, since run-in is considered a block display type.
124 // FIXME: Support transforms and reflections on inline flows someday.
125 setHasTransform(false);
126 setHasReflection(false);
129 static bool hasRelPositionedInlineAncestor(RenderObject* p)
131 while (p && p->isRenderInline()) {
132 if (p->isRelPositioned())
139 static void updateStyleOfAnonymousBlockContinuations(RenderObject* block, const RenderStyle* newStyle, const RenderStyle* oldStyle)
141 for (;block && block->isAnonymousBlock(); block = block->nextSibling()) {
142 if (!toRenderBlock(block)->isAnonymousBlockContinuation() || block->style()->position() == newStyle->position())
144 // If we are no longer relatively positioned but our descendant block(s) still have a relatively positioned ancestor then
145 // their containing anonymous block should keep its relative positioning.
146 RenderInline* cont = toRenderBlock(block)->inlineElementContinuation();
147 if (oldStyle->position() == RelativePosition && hasRelPositionedInlineAncestor(cont))
149 RefPtr<RenderStyle> blockStyle = RenderStyle::createAnonymousStyle(block->style());
150 blockStyle->setPosition(newStyle->position());
151 blockStyle->setDisplay(BLOCK);
152 block->setStyle(blockStyle);
156 void RenderInline::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
158 RenderBoxModelObject::styleDidChange(diff, oldStyle);
160 // Ensure that all of the split inlines pick up the new style. We
161 // only do this if we're an inline, since we don't want to propagate
162 // a block's style to the other inlines.
163 // e.g., <font>foo <h4>goo</h4> moo</font>. The <font> inlines before
164 // and after the block share the same style, but the block doesn't
165 // need to pass its style on to anyone else.
166 RenderStyle* newStyle = style();
167 RenderInline* continuation = inlineElementContinuation();
168 for (RenderInline* currCont = continuation; currCont; currCont = currCont->inlineElementContinuation()) {
169 RenderBoxModelObject* nextCont = currCont->continuation();
170 currCont->setContinuation(0);
171 currCont->setStyle(newStyle);
172 currCont->setContinuation(nextCont);
175 // If an inline's relative positioning has changed then any descendant blocks will need to change their relative positioning accordingly.
176 // Do this by updating the position of the descendant blocks' containing anonymous blocks - there may be more than one.
177 if (continuation && oldStyle && newStyle->position() != oldStyle->position()
178 && (newStyle->position() == RelativePosition || (oldStyle->position() == RelativePosition))) {
179 // If any descendant blocks exist then they will be in the next anonymous block and its siblings.
180 RenderObject* block = containingBlock()->nextSibling();
181 ASSERT(block && block->isAnonymousBlock());
182 updateStyleOfAnonymousBlockContinuations(block, newStyle, oldStyle);
185 if (!m_alwaysCreateLineBoxes) {
186 bool alwaysCreateLineBoxes = hasSelfPaintingLayer() || hasBoxDecorations() || newStyle->hasPadding() || newStyle->hasMargin() || hasOutline();
187 if (oldStyle && alwaysCreateLineBoxes) {
188 dirtyLineBoxes(false);
189 setNeedsLayout(true);
191 m_alwaysCreateLineBoxes = alwaysCreateLineBoxes;
194 // Update pseudos for :before and :after now.
195 if (!isAnonymous() && document()->usesBeforeAfterRules()) {
196 children()->updateBeforeAfterContent(this, BEFORE);
197 children()->updateBeforeAfterContent(this, AFTER);
201 void RenderInline::updateAlwaysCreateLineBoxes(bool fullLayout)
203 // Once we have been tainted once, just assume it will happen again. This way effects like hover highlighting that change the
204 // background color will only cause a layout on the first rollover.
205 if (m_alwaysCreateLineBoxes)
208 RenderStyle* parentStyle = parent()->style();
209 RenderInline* parentRenderInline = parent()->isRenderInline() ? toRenderInline(parent()) : 0;
210 bool checkFonts = document()->inNoQuirksMode();
211 bool alwaysCreateLineBoxes = (parentRenderInline && parentRenderInline->alwaysCreateLineBoxes())
212 || (parentRenderInline && parentStyle->verticalAlign() != BASELINE)
213 || style()->verticalAlign() != BASELINE
214 || style()->textEmphasisMark() != TextEmphasisMarkNone
215 || (checkFonts && (!parentStyle->font().fontMetrics().hasIdenticalAscentDescentAndLineGap(style()->font().fontMetrics())
216 || parentStyle->lineHeight() != style()->lineHeight()));
218 if (!alwaysCreateLineBoxes && checkFonts && document()->usesFirstLineRules()) {
219 // Have to check the first line style as well.
220 parentStyle = parent()->style(true);
221 RenderStyle* childStyle = style(true);
222 alwaysCreateLineBoxes = !parentStyle->font().fontMetrics().hasIdenticalAscentDescentAndLineGap(childStyle->font().fontMetrics())
223 || childStyle->verticalAlign() != BASELINE
224 || parentStyle->lineHeight() != childStyle->lineHeight();
227 if (alwaysCreateLineBoxes) {
229 dirtyLineBoxes(false);
230 m_alwaysCreateLineBoxes = true;
234 void RenderInline::addChild(RenderObject* newChild, RenderObject* beforeChild)
237 return addChildToContinuation(newChild, beforeChild);
238 return addChildIgnoringContinuation(newChild, beforeChild);
241 static RenderBoxModelObject* nextContinuation(RenderObject* renderer)
243 if (renderer->isInline() && !renderer->isReplaced())
244 return toRenderInline(renderer)->continuation();
245 return toRenderBlock(renderer)->inlineElementContinuation();
248 RenderBoxModelObject* RenderInline::continuationBefore(RenderObject* beforeChild)
250 if (beforeChild && beforeChild->parent() == this)
253 RenderBoxModelObject* curr = nextContinuation(this);
254 RenderBoxModelObject* nextToLast = this;
255 RenderBoxModelObject* last = this;
257 if (beforeChild && beforeChild->parent() == curr) {
258 if (curr->firstChild() == beforeChild)
265 curr = nextContinuation(curr);
268 if (!beforeChild && !last->firstChild())
273 void RenderInline::addChildIgnoringContinuation(RenderObject* newChild, RenderObject* beforeChild)
275 // Make sure we don't append things after :after-generated content if we have it.
276 if (!beforeChild && isAfterContent(lastChild()))
277 beforeChild = lastChild();
279 if (!newChild->isInline() && !newChild->isFloatingOrPositioned()) {
280 // We are placing a block inside an inline. We have to perform a split of this
281 // inline into continuations. This involves creating an anonymous block box to hold
282 // |newChild|. We then make that block box a continuation of this inline. We take all of
283 // the children after |beforeChild| and put them in a clone of this object.
284 RefPtr<RenderStyle> newStyle = RenderStyle::createAnonymousStyle(style());
285 newStyle->setDisplay(BLOCK);
287 // If inside an inline affected by relative positioning the block needs to be affected by it too.
288 // Giving the block a layer like this allows it to collect the x/y offsets from inline parents later.
289 if (hasRelPositionedInlineAncestor(this))
290 newStyle->setPosition(RelativePosition);
292 RenderBlock* newBox = new (renderArena()) RenderBlock(document() /* anonymous box */);
293 newBox->setStyle(newStyle.release());
294 RenderBoxModelObject* oldContinuation = continuation();
295 setContinuation(newBox);
297 // Someone may have put a <p> inside a <q>, causing a split. When this happens, the :after content
298 // has to move into the inline continuation. Call updateBeforeAfterContent to ensure that our :after
299 // content gets properly destroyed.
300 bool isLastChild = (beforeChild == lastChild());
301 if (document()->usesBeforeAfterRules())
302 children()->updateBeforeAfterContent(this, AFTER);
303 if (isLastChild && beforeChild != lastChild())
304 beforeChild = 0; // We destroyed the last child, so now we need to update our insertion
305 // point to be 0. It's just a straight append now.
307 splitFlow(beforeChild, newBox, newChild, oldContinuation);
311 RenderBoxModelObject::addChild(newChild, beforeChild);
313 newChild->setNeedsLayoutAndPrefWidthsRecalc();
316 RenderInline* RenderInline::cloneInline(RenderInline* src)
318 RenderInline* o = new (src->renderArena()) RenderInline(src->node());
319 o->setStyle(src->style());
323 void RenderInline::splitInlines(RenderBlock* fromBlock, RenderBlock* toBlock,
324 RenderBlock* middleBlock,
325 RenderObject* beforeChild, RenderBoxModelObject* oldCont)
327 // Create a clone of this inline.
328 RenderInline* clone = cloneInline(this);
329 clone->setContinuation(oldCont);
331 // Now take all of the children from beforeChild to the end and remove
332 // them from |this| and place them in the clone.
333 RenderObject* o = beforeChild;
335 RenderObject* tmp = o;
336 o = tmp->nextSibling();
337 clone->addChildIgnoringContinuation(children()->removeChildNode(this, tmp), 0);
338 tmp->setNeedsLayoutAndPrefWidthsRecalc();
341 // Hook |clone| up as the continuation of the middle block.
342 middleBlock->setContinuation(clone);
344 // We have been reparented and are now under the fromBlock. We need
345 // to walk up our inline parent chain until we hit the containing block.
346 // Once we hit the containing block we're done.
347 RenderBoxModelObject* curr = toRenderBoxModelObject(parent());
348 RenderBoxModelObject* currChild = this;
350 // FIXME: Because splitting is O(n^2) as tags nest pathologically, we cap the depth at which we're willing to clone.
351 // There will eventually be a better approach to this problem that will let us nest to a much
352 // greater depth (see bugzilla bug 13430) but for now we have a limit. This *will* result in
353 // incorrect rendering, but the alternative is to hang forever.
354 unsigned splitDepth = 1;
355 const unsigned cMaxSplitDepth = 200;
356 while (curr && curr != fromBlock) {
357 ASSERT(curr->isRenderInline());
358 if (splitDepth < cMaxSplitDepth) {
359 // Create a new clone.
360 RenderInline* cloneChild = clone;
361 clone = cloneInline(toRenderInline(curr));
363 // Insert our child clone as the first child.
364 clone->addChildIgnoringContinuation(cloneChild, 0);
366 // Hook the clone up as a continuation of |curr|.
367 RenderInline* inlineCurr = toRenderInline(curr);
368 oldCont = inlineCurr->continuation();
369 inlineCurr->setContinuation(clone);
370 clone->setContinuation(oldCont);
372 // Someone may have indirectly caused a <q> to split. When this happens, the :after content
373 // has to move into the inline continuation. Call updateBeforeAfterContent to ensure that the inline's :after
374 // content gets properly destroyed.
375 if (document()->usesBeforeAfterRules())
376 inlineCurr->children()->updateBeforeAfterContent(inlineCurr, AFTER);
378 // Now we need to take all of the children starting from the first child
379 // *after* currChild and append them all to the clone.
380 o = currChild->nextSibling();
382 RenderObject* tmp = o;
383 o = tmp->nextSibling();
384 clone->addChildIgnoringContinuation(inlineCurr->children()->removeChildNode(curr, tmp), 0);
385 tmp->setNeedsLayoutAndPrefWidthsRecalc();
389 // Keep walking up the chain.
391 curr = toRenderBoxModelObject(curr->parent());
395 // Now we are at the block level. We need to put the clone into the toBlock.
396 toBlock->children()->appendChildNode(toBlock, clone);
398 // Now take all the children after currChild and remove them from the fromBlock
399 // and put them in the toBlock.
400 o = currChild->nextSibling();
402 RenderObject* tmp = o;
403 o = tmp->nextSibling();
404 toBlock->children()->appendChildNode(toBlock, fromBlock->children()->removeChildNode(fromBlock, tmp));
408 void RenderInline::splitFlow(RenderObject* beforeChild, RenderBlock* newBlockBox,
409 RenderObject* newChild, RenderBoxModelObject* oldCont)
411 RenderBlock* pre = 0;
412 RenderBlock* block = containingBlock();
414 // Delete our line boxes before we do the inline split into continuations.
415 block->deleteLineBoxTree();
417 bool madeNewBeforeBlock = false;
418 if (block->isAnonymousBlock() && (!block->parent() || !block->parent()->createsAnonymousWrapper())) {
419 // We can reuse this block and make it the preBlock of the next continuation.
421 pre->removePositionedObjects(0);
422 block = block->containingBlock();
424 // No anonymous block available for use. Make one.
425 pre = block->createAnonymousBlock();
426 madeNewBeforeBlock = true;
429 RenderBlock* post = toRenderBlock(pre->createAnonymousBoxWithSameTypeAs(block));
431 RenderObject* boxFirst = madeNewBeforeBlock ? block->firstChild() : pre->nextSibling();
432 if (madeNewBeforeBlock)
433 block->children()->insertChildNode(block, pre, boxFirst);
434 block->children()->insertChildNode(block, newBlockBox, boxFirst);
435 block->children()->insertChildNode(block, post, boxFirst);
436 block->setChildrenInline(false);
438 if (madeNewBeforeBlock) {
439 RenderObject* o = boxFirst;
441 RenderObject* no = o;
442 o = no->nextSibling();
443 pre->children()->appendChildNode(pre, block->children()->removeChildNode(block, no));
444 no->setNeedsLayoutAndPrefWidthsRecalc();
448 splitInlines(pre, post, newBlockBox, beforeChild, oldCont);
450 // We already know the newBlockBox isn't going to contain inline kids, so avoid wasting
451 // time in makeChildrenNonInline by just setting this explicitly up front.
452 newBlockBox->setChildrenInline(false);
454 // We delayed adding the newChild until now so that the |newBlockBox| would be fully
455 // connected, thus allowing newChild access to a renderArena should it need
456 // to wrap itself in additional boxes (e.g., table construction).
457 newBlockBox->addChild(newChild);
459 // Always just do a full layout in order to ensure that line boxes (especially wrappers for images)
460 // get deleted properly. Because objects moves from the pre block into the post block, we want to
461 // make new line boxes instead of leaving the old line boxes around.
462 pre->setNeedsLayoutAndPrefWidthsRecalc();
463 block->setNeedsLayoutAndPrefWidthsRecalc();
464 post->setNeedsLayoutAndPrefWidthsRecalc();
467 void RenderInline::addChildToContinuation(RenderObject* newChild, RenderObject* beforeChild)
469 RenderBoxModelObject* flow = continuationBefore(beforeChild);
470 ASSERT(!beforeChild || beforeChild->parent()->isRenderBlock() || beforeChild->parent()->isRenderInline());
471 RenderBoxModelObject* beforeChildParent = 0;
473 beforeChildParent = toRenderBoxModelObject(beforeChild->parent());
475 RenderBoxModelObject* cont = nextContinuation(flow);
477 beforeChildParent = cont;
479 beforeChildParent = flow;
482 if (newChild->isFloatingOrPositioned())
483 return beforeChildParent->addChildIgnoringContinuation(newChild, beforeChild);
485 // A continuation always consists of two potential candidates: an inline or an anonymous
486 // block box holding block children.
487 bool childInline = newChild->isInline();
488 bool bcpInline = beforeChildParent->isInline();
489 bool flowInline = flow->isInline();
491 if (flow == beforeChildParent)
492 return flow->addChildIgnoringContinuation(newChild, beforeChild);
494 // The goal here is to match up if we can, so that we can coalesce and create the
495 // minimal # of continuations needed for the inline.
496 if (childInline == bcpInline)
497 return beforeChildParent->addChildIgnoringContinuation(newChild, beforeChild);
498 else if (flowInline == childInline)
499 return flow->addChildIgnoringContinuation(newChild, 0); // Just treat like an append.
501 return beforeChildParent->addChildIgnoringContinuation(newChild, beforeChild);
505 void RenderInline::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
507 m_lineBoxes.paint(this, paintInfo, paintOffset);
510 void RenderInline::absoluteRects(Vector<IntRect>& rects, const LayoutPoint& accumulatedOffset) const
512 if (!alwaysCreateLineBoxes())
513 culledInlineAbsoluteRects(this, rects, toLayoutSize(accumulatedOffset));
514 else if (InlineFlowBox* curr = firstLineBox()) {
515 for (; curr; curr = curr->nextLineBox())
516 rects.append(enclosingIntRect(FloatRect(accumulatedOffset + curr->topLeft(), curr->size())));
518 rects.append(IntRect(roundedIntPoint(accumulatedOffset), IntSize()));
520 if (continuation()) {
521 if (continuation()->isBox()) {
522 RenderBox* box = toRenderBox(continuation());
523 continuation()->absoluteRects(rects, toLayoutPoint(accumulatedOffset - containingBlock()->location() + box->size()));
525 continuation()->absoluteRects(rects, toLayoutPoint(accumulatedOffset - containingBlock()->location()));
529 void RenderInline::culledInlineAbsoluteRects(const RenderInline* container, Vector<IntRect>& rects, const LayoutSize& offset) const
531 if (!culledInlineFirstLineBox()) {
532 rects.append(IntRect(offset.width(), offset.height(), 0, 0));
536 bool isHorizontal = style()->isHorizontalWritingMode();
537 for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) {
538 if (curr->isFloatingOrPositioned())
541 // We want to get the margin box in the inline direction, and then use our font ascent/descent in the block
542 // direction (aligned to the root box's baseline).
544 RenderBox* currBox = toRenderBox(curr);
545 if (currBox->inlineBoxWrapper()) {
546 RootInlineBox* rootBox = currBox->inlineBoxWrapper()->root();
547 int logicalTop = rootBox->logicalTop() + (rootBox->renderer()->style(rootBox->isFirstLineStyle())->font().fontMetrics().ascent() - container->style(rootBox->isFirstLineStyle())->font().fontMetrics().ascent());
548 int logicalHeight = container->style(rootBox->isFirstLineStyle())->font().fontMetrics().height();
551 result = FloatRect(offset.width() + currBox->inlineBoxWrapper()->x() - currBox->marginLeft(), offset.height() + logicalTop, currBox->width() + currBox->marginWidth(), logicalHeight);
553 result = FloatRect(offset.width() + logicalTop, offset.height() + currBox->inlineBoxWrapper()->y() - currBox->marginTop(), logicalHeight, currBox->height() + currBox->marginHeight());
554 rects.append(enclosingIntRect(result));
556 } else if (curr->isRenderInline()) {
557 // If the child doesn't need line boxes either, then we can recur.
558 RenderInline* currInline = toRenderInline(curr);
559 if (!currInline->alwaysCreateLineBoxes())
560 currInline->culledInlineAbsoluteRects(container, rects, offset);
562 for (InlineFlowBox* childLine = currInline->firstLineBox(); childLine; childLine = childLine->nextLineBox()) {
563 RootInlineBox* rootBox = childLine->root();
564 int logicalTop = rootBox->logicalTop() + (rootBox->renderer()->style(rootBox->isFirstLineStyle())->font().fontMetrics().ascent() - container->style(rootBox->isFirstLineStyle())->font().fontMetrics().ascent());
565 int logicalHeight = container->style(rootBox->isFirstLineStyle())->font().fontMetrics().height();
568 result = FloatRect(offset.width() + childLine->x() - childLine->marginLogicalLeft(),
569 offset.height() + logicalTop,
570 childLine->logicalWidth() + childLine->marginLogicalLeft() + childLine->marginLogicalRight(),
573 result = FloatRect(offset.width() + logicalTop,
574 offset.height() + childLine->y() - childLine->marginLogicalLeft(),
576 childLine->logicalWidth() + childLine->marginLogicalLeft() + childLine->marginLogicalRight());
577 rects.append(enclosingIntRect(result));
580 } else if (curr->isText()) {
581 RenderText* currText = toRenderText(curr);
582 for (InlineTextBox* childText = currText->firstTextBox(); childText; childText = childText->nextTextBox()) {
583 RootInlineBox* rootBox = childText->root();
584 int logicalTop = rootBox->logicalTop() + (rootBox->renderer()->style(rootBox->isFirstLineStyle())->font().fontMetrics().ascent() - container->style(rootBox->isFirstLineStyle())->font().fontMetrics().ascent());
585 int logicalHeight = container->style(rootBox->isFirstLineStyle())->font().fontMetrics().height();
588 result = FloatRect(offset.width() + childText->x(), offset.height() + logicalTop, childText->logicalWidth(), logicalHeight);
590 result = FloatRect(offset.width() + logicalTop, offset.height() + childText->y(), logicalHeight, childText->logicalWidth());
591 rects.append(enclosingIntRect(result));
597 void RenderInline::absoluteQuads(Vector<FloatQuad>& quads, bool* wasFixed) const
599 if (!alwaysCreateLineBoxes())
600 culledInlineAbsoluteQuads(this, quads);
601 else if (InlineFlowBox* curr = firstLineBox()) {
602 for (; curr; curr = curr->nextLineBox()) {
603 FloatRect localRect(curr->x(), curr->y(), curr->width(), curr->height());
604 quads.append(localToAbsoluteQuad(localRect, false, wasFixed));
607 quads.append(localToAbsoluteQuad(FloatRect(), false, wasFixed));
610 continuation()->absoluteQuads(quads, wasFixed);
613 void RenderInline::culledInlineAbsoluteQuads(const RenderInline* container, Vector<FloatQuad>& quads) const
615 if (!culledInlineFirstLineBox()) {
616 quads.append(localToAbsoluteQuad(FloatRect()));
620 bool isHorizontal = style()->isHorizontalWritingMode();
621 for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) {
622 if (curr->isFloatingOrPositioned())
625 // We want to get the margin box in the inline direction, and then use our font ascent/descent in the block
626 // direction (aligned to the root box's baseline).
628 RenderBox* currBox = toRenderBox(curr);
629 if (currBox->inlineBoxWrapper()) {
630 RootInlineBox* rootBox = currBox->inlineBoxWrapper()->root();
631 int logicalTop = rootBox->logicalTop() + (rootBox->renderer()->style(rootBox->isFirstLineStyle())->font().fontMetrics().ascent() - container->style(rootBox->isFirstLineStyle())->font().fontMetrics().ascent());
632 int logicalHeight = container->style(rootBox->isFirstLineStyle())->font().fontMetrics().height();
635 result = FloatRect(currBox->inlineBoxWrapper()->x() - currBox->marginLeft(), logicalTop, currBox->width() + currBox->marginWidth(), logicalHeight);
637 result = FloatRect(logicalTop, currBox->inlineBoxWrapper()->y() - currBox->marginTop(), logicalHeight, currBox->height() + currBox->marginHeight());
638 quads.append(localToAbsoluteQuad(result));
640 } else if (curr->isRenderInline()) {
641 // If the child doesn't need line boxes either, then we can recur.
642 RenderInline* currInline = toRenderInline(curr);
643 if (!currInline->alwaysCreateLineBoxes())
644 currInline->culledInlineAbsoluteQuads(container, quads);
646 for (InlineFlowBox* childLine = currInline->firstLineBox(); childLine; childLine = childLine->nextLineBox()) {
647 RootInlineBox* rootBox = childLine->root();
648 int logicalTop = rootBox->logicalTop() + (rootBox->renderer()->style(rootBox->isFirstLineStyle())->font().fontMetrics().ascent() - container->style(rootBox->isFirstLineStyle())->font().fontMetrics().ascent());
649 int logicalHeight = container->style(rootBox->isFirstLineStyle())->font().fontMetrics().height();
652 result = FloatRect(childLine->x() - childLine->marginLogicalLeft(),
654 childLine->logicalWidth() + childLine->marginLogicalLeft() + childLine->marginLogicalRight(),
657 result = FloatRect(logicalTop,
658 childLine->y() - childLine->marginLogicalLeft(),
660 childLine->logicalWidth() + childLine->marginLogicalLeft() + childLine->marginLogicalRight());
661 quads.append(localToAbsoluteQuad(result));
664 } else if (curr->isText()) {
665 RenderText* currText = toRenderText(curr);
666 for (InlineTextBox* childText = currText->firstTextBox(); childText; childText = childText->nextTextBox()) {
667 RootInlineBox* rootBox = childText->root();
668 int logicalTop = rootBox->logicalTop() + (rootBox->renderer()->style(rootBox->isFirstLineStyle())->font().fontMetrics().ascent() - container->style(rootBox->isFirstLineStyle())->font().fontMetrics().ascent());
669 int logicalHeight = container->style(rootBox->isFirstLineStyle())->font().fontMetrics().height();
672 result = FloatRect(childText->x(), logicalTop, childText->logicalWidth(), logicalHeight);
674 result = FloatRect(logicalTop, childText->y(), logicalHeight, childText->logicalWidth());
675 quads.append(localToAbsoluteQuad(result));
681 LayoutUnit RenderInline::offsetLeft() const
683 LayoutUnit x = RenderBoxModelObject::offsetLeft();
684 if (InlineBox* firstBox = firstLineBoxIncludingCulling())
689 LayoutUnit RenderInline::offsetTop() const
691 LayoutUnit y = RenderBoxModelObject::offsetTop();
692 if (InlineBox* firstBox = firstLineBoxIncludingCulling())
697 static LayoutUnit computeMargin(const RenderInline* renderer, const Length& margin)
701 if (margin.isFixed())
702 return margin.value();
703 if (margin.isPercent())
704 return minimumValueForLength(margin, max<LayoutUnit>(0, renderer->containingBlock()->availableLogicalWidth()));
705 if (margin.isViewportPercentage())
706 return valueForLength(margin, 0, renderer->view());
710 LayoutUnit RenderInline::marginLeft() const
712 return computeMargin(this, style()->marginLeft());
715 LayoutUnit RenderInline::marginRight() const
717 return computeMargin(this, style()->marginRight());
720 LayoutUnit RenderInline::marginTop() const
722 return computeMargin(this, style()->marginTop());
725 LayoutUnit RenderInline::marginBottom() const
727 return computeMargin(this, style()->marginBottom());
730 LayoutUnit RenderInline::marginStart() const
732 return computeMargin(this, style()->marginStart());
735 LayoutUnit RenderInline::marginEnd() const
737 return computeMargin(this, style()->marginEnd());
740 LayoutUnit RenderInline::marginBefore() const
742 return computeMargin(this, style()->marginBefore());
745 LayoutUnit RenderInline::marginAfter() const
747 return computeMargin(this, style()->marginAfter());
750 const char* RenderInline::renderName() const
752 if (isRelPositioned())
753 return "RenderInline (relative positioned)";
755 return "RenderInline (generated)";
757 return "RenderInline (run-in)";
758 return "RenderInline";
761 bool RenderInline::nodeAtPoint(const HitTestRequest& request, HitTestResult& result,
762 const LayoutPoint& pointInContainer, const LayoutPoint& accumulatedOffset, HitTestAction hitTestAction)
764 return m_lineBoxes.hitTest(this, request, result, pointInContainer, accumulatedOffset, hitTestAction);
767 VisiblePosition RenderInline::positionForPoint(const LayoutPoint& point)
769 // FIXME: Does not deal with relative positioned inlines (should it?)
770 RenderBlock* cb = containingBlock();
771 if (firstLineBox()) {
772 // This inline actually has a line box. We must have clicked in the border/padding of one of these boxes. We
773 // should try to find a result by asking our containing block.
774 return cb->positionForPoint(point);
777 // Translate the coords from the pre-anonymous block to the post-anonymous block.
778 LayoutPoint parentBlockPoint = cb->location() + point;
779 RenderBoxModelObject* c = continuation();
781 RenderBox* contBlock = c->isInline() ? c->containingBlock() : toRenderBlock(c);
782 if (c->isInline() || c->firstChild())
783 return c->positionForPoint(parentBlockPoint - contBlock->locationOffset());
784 c = toRenderBlock(c)->inlineElementContinuation();
787 return RenderBoxModelObject::positionForPoint(point);
790 IntRect RenderInline::linesBoundingBox() const
792 if (!alwaysCreateLineBoxes()) {
793 ASSERT(!firstLineBox());
794 return enclosingIntRect(culledInlineBoundingBox(this));
799 // 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
800 // 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
801 // builds and help us someday figure out why. We also put in a redundant check of lastLineBox() to avoid the crash for now.
802 ASSERT(!firstLineBox() == !lastLineBox()); // Either both are null or both exist.
803 if (firstLineBox() && lastLineBox()) {
804 // Return the width of the minimal left side and the maximal right side.
805 float logicalLeftSide = 0;
806 float logicalRightSide = 0;
807 for (InlineFlowBox* curr = firstLineBox(); curr; curr = curr->nextLineBox()) {
808 if (curr == firstLineBox() || curr->logicalLeft() < logicalLeftSide)
809 logicalLeftSide = curr->logicalLeft();
810 if (curr == firstLineBox() || curr->logicalRight() > logicalRightSide)
811 logicalRightSide = curr->logicalRight();
814 bool isHorizontal = style()->isHorizontalWritingMode();
816 float x = isHorizontal ? logicalLeftSide : firstLineBox()->x();
817 float y = isHorizontal ? firstLineBox()->y() : logicalLeftSide;
818 float width = isHorizontal ? logicalRightSide - logicalLeftSide : lastLineBox()->logicalBottom() - x;
819 float height = isHorizontal ? lastLineBox()->logicalBottom() - y : logicalRightSide - logicalLeftSide;
820 result = enclosingIntRect(FloatRect(x, y, width, height));
826 FloatRect RenderInline::culledInlineBoundingBox(const RenderInline* container) const
829 bool isHorizontal = style()->isHorizontalWritingMode();
830 for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) {
831 if (curr->isFloatingOrPositioned())
834 // We want to get the margin box in the inline direction, and then use our font ascent/descent in the block
835 // direction (aligned to the root box's baseline).
837 RenderBox* currBox = toRenderBox(curr);
838 if (currBox->inlineBoxWrapper()) {
839 RootInlineBox* rootBox = currBox->inlineBoxWrapper()->root();
840 int logicalTop = rootBox->logicalTop() + (rootBox->renderer()->style(rootBox->isFirstLineStyle())->font().fontMetrics().ascent() - container->style(rootBox->isFirstLineStyle())->font().fontMetrics().ascent());
841 int logicalHeight = container->style(rootBox->isFirstLineStyle())->font().fontMetrics().height();
843 result.uniteIfNonZero(FloatRect(currBox->inlineBoxWrapper()->x() - currBox->marginLeft(), logicalTop, currBox->width() + currBox->marginWidth(), logicalHeight));
845 result.uniteIfNonZero(FloatRect(logicalTop, currBox->inlineBoxWrapper()->y() - currBox->marginTop(), logicalHeight, currBox->height() + currBox->marginHeight()));
847 } else if (curr->isRenderInline()) {
848 // If the child doesn't need line boxes either, then we can recur.
849 RenderInline* currInline = toRenderInline(curr);
850 if (!currInline->alwaysCreateLineBoxes())
851 result.uniteIfNonZero(currInline->culledInlineBoundingBox(container));
853 for (InlineFlowBox* childLine = currInline->firstLineBox(); childLine; childLine = childLine->nextLineBox()) {
854 RootInlineBox* rootBox = childLine->root();
855 int logicalTop = rootBox->logicalTop() + (rootBox->renderer()->style(rootBox->isFirstLineStyle())->font().fontMetrics().ascent() - container->style(rootBox->isFirstLineStyle())->font().fontMetrics().ascent());
856 int logicalHeight = container->style(rootBox->isFirstLineStyle())->font().fontMetrics().height();
858 result.uniteIfNonZero(FloatRect(childLine->x() - childLine->marginLogicalLeft(),
860 childLine->logicalWidth() + childLine->marginLogicalLeft() + childLine->marginLogicalRight(),
863 result.uniteIfNonZero(FloatRect(logicalTop,
864 childLine->y() - childLine->marginLogicalLeft(),
866 childLine->logicalWidth() + childLine->marginLogicalLeft() + childLine->marginLogicalRight()));
870 } else if (curr->isText()) {
871 RenderText* currText = toRenderText(curr);
872 for (InlineTextBox* childText = currText->firstTextBox(); childText; childText = childText->nextTextBox()) {
873 RootInlineBox* rootBox = childText->root();
874 int logicalTop = rootBox->logicalTop() + (rootBox->renderer()->style(rootBox->isFirstLineStyle())->font().fontMetrics().ascent() - container->style(rootBox->isFirstLineStyle())->font().fontMetrics().ascent());
875 int logicalHeight = container->style(rootBox->isFirstLineStyle())->font().fontMetrics().height();
877 result.uniteIfNonZero(FloatRect(childText->x(), logicalTop, childText->logicalWidth(), logicalHeight));
879 result.uniteIfNonZero(FloatRect(logicalTop, childText->y(), logicalHeight, childText->logicalWidth()));
883 return enclosingLayoutRect(result);
886 InlineBox* RenderInline::culledInlineFirstLineBox() const
888 for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) {
889 if (curr->isFloatingOrPositioned())
892 // We want to get the margin box in the inline direction, and then use our font ascent/descent in the block
893 // direction (aligned to the root box's baseline).
895 return toRenderBox(curr)->inlineBoxWrapper();
896 if (curr->isRenderInline()) {
897 RenderInline* currInline = toRenderInline(curr);
898 InlineBox* result = currInline->firstLineBoxIncludingCulling();
901 } else if (curr->isText()) {
902 RenderText* currText = toRenderText(curr);
903 if (currText->firstTextBox())
904 return currText->firstTextBox();
910 InlineBox* RenderInline::culledInlineLastLineBox() const
912 for (RenderObject* curr = lastChild(); curr; curr = curr->previousSibling()) {
913 if (curr->isFloatingOrPositioned())
916 // We want to get the margin box in the inline direction, and then use our font ascent/descent in the block
917 // direction (aligned to the root box's baseline).
919 return toRenderBox(curr)->inlineBoxWrapper();
920 if (curr->isRenderInline()) {
921 RenderInline* currInline = toRenderInline(curr);
922 InlineBox* result = currInline->lastLineBoxIncludingCulling();
925 } else if (curr->isText()) {
926 RenderText* currText = toRenderText(curr);
927 if (currText->lastTextBox())
928 return currText->lastTextBox();
934 LayoutRect RenderInline::culledInlineVisualOverflowBoundingBox() const
936 LayoutRect result(culledInlineBoundingBox(this));
937 bool isHorizontal = style()->isHorizontalWritingMode();
938 for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) {
939 if (curr->isFloatingOrPositioned())
942 // For overflow we just have to propagate by hand and recompute it all.
944 RenderBox* currBox = toRenderBox(curr);
945 if (!currBox->hasSelfPaintingLayer() && currBox->inlineBoxWrapper()) {
946 LayoutRect logicalRect = currBox->logicalVisualOverflowRectForPropagation(style());
948 logicalRect.moveBy(currBox->location());
949 result.uniteIfNonZero(logicalRect);
951 logicalRect.moveBy(currBox->location());
952 result.uniteIfNonZero(logicalRect.transposedRect());
955 } else if (curr->isRenderInline()) {
956 // If the child doesn't need line boxes either, then we can recur.
957 RenderInline* currInline = toRenderInline(curr);
958 if (!currInline->alwaysCreateLineBoxes())
959 result.uniteIfNonZero(currInline->culledInlineVisualOverflowBoundingBox());
960 else if (!currInline->hasSelfPaintingLayer())
961 result.uniteIfNonZero(currInline->linesVisualOverflowBoundingBox());
962 } else if (curr->isText()) {
963 // FIXME; Overflow from text boxes is lost. We will need to cache this information in
965 RenderText* currText = toRenderText(curr);
966 result.uniteIfNonZero(currText->linesVisualOverflowBoundingBox());
972 LayoutRect RenderInline::linesVisualOverflowBoundingBox() const
974 if (!alwaysCreateLineBoxes())
975 return culledInlineVisualOverflowBoundingBox();
977 if (!firstLineBox() || !lastLineBox())
980 // Return the width of the minimal left side and the maximal right side.
981 LayoutUnit logicalLeftSide = MAX_LAYOUT_UNIT;
982 LayoutUnit logicalRightSide = MIN_LAYOUT_UNIT;
983 for (InlineFlowBox* curr = firstLineBox(); curr; curr = curr->nextLineBox()) {
984 logicalLeftSide = min(logicalLeftSide, curr->logicalLeftVisualOverflow());
985 logicalRightSide = max(logicalRightSide, curr->logicalRightVisualOverflow());
988 RootInlineBox* firstRootBox = firstLineBox()->root();
989 RootInlineBox* lastRootBox = lastLineBox()->root();
991 LayoutUnit logicalTop = firstLineBox()->logicalTopVisualOverflow(firstRootBox->lineTop());
992 LayoutUnit logicalWidth = logicalRightSide - logicalLeftSide;
993 LayoutUnit logicalHeight = lastLineBox()->logicalBottomVisualOverflow(lastRootBox->lineBottom()) - logicalTop;
995 LayoutRect rect(logicalLeftSide, logicalTop, logicalWidth, logicalHeight);
996 if (!style()->isHorizontalWritingMode())
997 rect = rect.transposedRect();
1001 LayoutRect RenderInline::clippedOverflowRectForRepaint(RenderBoxModelObject* repaintContainer) const
1003 // Only run-ins are allowed in here during layout.
1004 ASSERT(!view() || !view()->layoutStateEnabled() || isRunIn());
1006 if (!firstLineBoxIncludingCulling() && !continuation())
1007 return LayoutRect();
1009 // Find our leftmost position.
1010 LayoutRect boundingBox(linesVisualOverflowBoundingBox());
1011 LayoutUnit left = boundingBox.x();
1012 LayoutUnit top = boundingBox.y();
1014 // Now invalidate a rectangle.
1015 LayoutUnit ow = style() ? style()->outlineSize() : 0;
1017 bool hitRepaintContainer = false;
1019 // We need to add in the relative position offsets of any inlines (including us) up to our
1020 // containing block.
1021 RenderBlock* cb = containingBlock();
1022 for (const RenderObject* inlineFlow = this; inlineFlow && inlineFlow->isRenderInline() && inlineFlow != cb;
1023 inlineFlow = inlineFlow->parent()) {
1024 if (inlineFlow == repaintContainer) {
1025 hitRepaintContainer = true;
1028 if (inlineFlow->style()->position() == RelativePosition && inlineFlow->hasLayer())
1029 toRenderInline(inlineFlow)->layer()->relativePositionOffset(left, top);
1032 LayoutRect r(-ow + left, -ow + top, boundingBox.width() + ow * 2, boundingBox.height() + ow * 2);
1034 if (hitRepaintContainer || !cb)
1037 if (cb->hasColumns())
1038 cb->adjustRectForColumns(r);
1040 if (cb->hasOverflowClip()) {
1041 // cb->height() is inaccurate if we're in the middle of a layout of |cb|, so use the
1042 // layer's size instead. Even if the layer's size is wrong, the layer itself will repaint
1043 // anyway if its size does change.
1044 LayoutRect repaintRect(r);
1045 repaintRect.move(-cb->scrolledContentOffset()); // For overflow:auto/scroll/hidden.
1047 LayoutRect boxRect(LayoutPoint(), cb->cachedSizeForOverflowClip());
1048 r = intersection(repaintRect, boxRect);
1051 cb->computeRectForRepaint(repaintContainer, r);
1054 for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) {
1055 if (!curr->isText()) {
1056 LayoutRect childRect = curr->rectWithOutlineForRepaint(repaintContainer, ow);
1061 if (continuation() && !continuation()->isInline() && continuation()->parent()) {
1062 LayoutRect contRect = continuation()->rectWithOutlineForRepaint(repaintContainer, ow);
1070 LayoutRect RenderInline::rectWithOutlineForRepaint(RenderBoxModelObject* repaintContainer, LayoutUnit outlineWidth) const
1072 LayoutRect r(RenderBoxModelObject::rectWithOutlineForRepaint(repaintContainer, outlineWidth));
1073 for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) {
1074 if (!curr->isText())
1075 r.unite(curr->rectWithOutlineForRepaint(repaintContainer, outlineWidth));
1080 void RenderInline::computeRectForRepaint(RenderBoxModelObject* repaintContainer, LayoutRect& rect, bool fixed) const
1082 if (RenderView* v = view()) {
1083 // LayoutState is only valid for root-relative repainting
1084 if (v->layoutStateEnabled() && !repaintContainer) {
1085 LayoutState* layoutState = v->layoutState();
1086 if (style()->position() == RelativePosition && layer())
1087 rect.move(layer()->relativePositionOffset());
1088 rect.move(layoutState->m_paintOffset);
1089 if (layoutState->m_clipped)
1090 rect.intersect(layoutState->m_clipRect);
1095 if (repaintContainer == this)
1098 bool containerSkipped;
1099 RenderObject* o = container(repaintContainer, &containerSkipped);
1103 LayoutPoint topLeft = rect.location();
1105 if (o->isBlockFlow() && !style()->isPositioned()) {
1106 RenderBlock* cb = toRenderBlock(o);
1107 if (cb->hasColumns()) {
1108 LayoutRect repaintRect(topLeft, rect.size());
1109 cb->adjustRectForColumns(repaintRect);
1110 topLeft = repaintRect.location();
1115 if (style()->position() == RelativePosition && layer()) {
1116 // Apply the relative position offset when invalidating a rectangle. The layer
1117 // is translated, but the render box isn't, so we need to do this to get the
1118 // right dirty rect. Since this is called from RenderObject::setStyle, the relative position
1119 // flag on the RenderObject has been cleared, so use the one on the style().
1120 topLeft += layer()->relativePositionOffset();
1123 // FIXME: We ignore the lightweight clipping rect that controls use, since if |o| is in mid-layout,
1124 // its controlClipRect will be wrong. For overflow clip we use the values cached by the layer.
1125 if (o->hasOverflowClip()) {
1126 RenderBox* containerBox = toRenderBox(o);
1128 // o->height() is inaccurate if we're in the middle of a layout of |o|, so use the
1129 // layer's size instead. Even if the layer's size is wrong, the layer itself will repaint
1130 // anyway if its size does change.
1131 topLeft -= containerBox->scrolledContentOffset(); // For overflow:auto/scroll/hidden.
1133 LayoutRect repaintRect(topLeft, rect.size());
1134 LayoutRect boxRect(LayoutPoint(), containerBox->cachedSizeForOverflowClip());
1135 rect = intersection(repaintRect, boxRect);
1139 rect.setLocation(topLeft);
1141 if (containerSkipped) {
1142 // If the repaintContainer is below o, then we need to map the rect into repaintContainer's coordinates.
1143 LayoutSize containerOffset = repaintContainer->offsetFromAncestorContainer(o);
1144 rect.move(-containerOffset);
1148 o->computeRectForRepaint(repaintContainer, rect, fixed);
1151 LayoutSize RenderInline::offsetFromContainer(RenderObject* container, const LayoutPoint& point) const
1153 ASSERT(container == this->container());
1156 if (isRelPositioned())
1157 offset += relativePositionOffset();
1159 container->adjustForColumns(offset, point);
1161 if (container->hasOverflowClip())
1162 offset -= toRenderBox(container)->scrolledContentOffset();
1167 void RenderInline::mapLocalToContainer(RenderBoxModelObject* repaintContainer, bool fixed, bool useTransforms, TransformState& transformState, bool* wasFixed) const
1169 if (repaintContainer == this)
1172 if (RenderView *v = view()) {
1173 if (v->layoutStateEnabled() && !repaintContainer) {
1174 LayoutState* layoutState = v->layoutState();
1175 LayoutSize offset = layoutState->m_paintOffset;
1176 if (style()->position() == RelativePosition && layer())
1177 offset += layer()->relativePositionOffset();
1178 transformState.move(offset);
1183 bool containerSkipped;
1184 RenderObject* o = container(repaintContainer, &containerSkipped);
1188 IntPoint centerPoint = roundedIntPoint(transformState.mappedPoint());
1189 if (o->isBox() && o->style()->isFlippedBlocksWritingMode())
1190 transformState.move(toRenderBox(o)->flipForWritingModeIncludingColumns(roundedIntPoint(transformState.mappedPoint())) - centerPoint);
1192 LayoutSize containerOffset = offsetFromContainer(o, roundedLayoutPoint(transformState.mappedPoint()));
1194 bool preserve3D = useTransforms && (o->style()->preserves3D() || style()->preserves3D());
1195 if (useTransforms && shouldUseTransformFromContainer(o)) {
1196 TransformationMatrix t;
1197 getTransformFromContainer(o, containerOffset, t);
1198 transformState.applyTransform(t, preserve3D ? TransformState::AccumulateTransform : TransformState::FlattenTransform);
1200 transformState.move(containerOffset.width(), containerOffset.height(), preserve3D ? TransformState::AccumulateTransform : TransformState::FlattenTransform);
1202 if (containerSkipped) {
1203 // There can't be a transform between repaintContainer and o, because transforms create containers, so it should be safe
1204 // to just subtract the delta between the repaintContainer and o.
1205 LayoutSize containerOffset = repaintContainer->offsetFromAncestorContainer(o);
1206 transformState.move(-containerOffset.width(), -containerOffset.height(), preserve3D ? TransformState::AccumulateTransform : TransformState::FlattenTransform);
1210 o->mapLocalToContainer(repaintContainer, fixed, useTransforms, transformState, wasFixed);
1213 void RenderInline::updateDragState(bool dragOn)
1215 RenderBoxModelObject::updateDragState(dragOn);
1217 continuation()->updateDragState(dragOn);
1220 void RenderInline::childBecameNonInline(RenderObject* child)
1222 // We have to split the parent flow.
1223 RenderBlock* newBox = containingBlock()->createAnonymousBlock();
1224 RenderBoxModelObject* oldContinuation = continuation();
1225 setContinuation(newBox);
1226 RenderObject* beforeChild = child->nextSibling();
1227 children()->removeChildNode(this, child);
1228 splitFlow(beforeChild, newBox, child, oldContinuation);
1231 void RenderInline::updateHitTestResult(HitTestResult& result, const LayoutPoint& point)
1233 if (result.innerNode())
1237 LayoutPoint localPoint(point);
1239 if (isInlineElementContinuation()) {
1240 // We're in the continuation of a split inline. Adjust our local point to be in the coordinate space
1241 // of the principal renderer's containing block. This will end up being the innerNonSharedNode.
1242 RenderBlock* firstBlock = n->renderer()->containingBlock();
1244 // Get our containing block.
1245 RenderBox* block = containingBlock();
1246 localPoint.move(block->x() - firstBlock->x(), block->y() - firstBlock->y());
1249 result.setInnerNode(n);
1250 if (!result.innerNonSharedNode())
1251 result.setInnerNonSharedNode(n);
1252 result.setLocalPoint(localPoint);
1256 void RenderInline::dirtyLineBoxes(bool fullLayout)
1259 m_lineBoxes.deleteLineBoxes(renderArena());
1263 if (!alwaysCreateLineBoxes()) {
1264 // We have to grovel into our children in order to dirty the appropriate lines.
1265 for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) {
1266 if (curr->isFloatingOrPositioned())
1268 if (curr->isBox() && !curr->needsLayout()) {
1269 RenderBox* currBox = toRenderBox(curr);
1270 if (currBox->inlineBoxWrapper())
1271 currBox->inlineBoxWrapper()->root()->markDirty();
1272 } else if (!curr->selfNeedsLayout()) {
1273 if (curr->isRenderInline()) {
1274 RenderInline* currInline = toRenderInline(curr);
1275 for (InlineFlowBox* childLine = currInline->firstLineBox(); childLine; childLine = childLine->nextLineBox())
1276 childLine->root()->markDirty();
1277 } else if (curr->isText()) {
1278 RenderText* currText = toRenderText(curr);
1279 for (InlineTextBox* childText = currText->firstTextBox(); childText; childText = childText->nextTextBox())
1280 childText->root()->markDirty();
1285 m_lineBoxes.dirtyLineBoxes();
1288 InlineFlowBox* RenderInline::createInlineFlowBox()
1290 return new (renderArena()) InlineFlowBox(this);
1293 InlineFlowBox* RenderInline::createAndAppendInlineFlowBox()
1295 setAlwaysCreateLineBoxes();
1296 InlineFlowBox* flowBox = createInlineFlowBox();
1297 m_lineBoxes.appendLineBox(flowBox);
1301 LayoutUnit RenderInline::lineHeight(bool firstLine, LineDirectionMode /*direction*/, LinePositionMode /*linePositionMode*/) const
1303 if (firstLine && document()->usesFirstLineRules()) {
1304 RenderStyle* s = style(firstLine);
1306 return s->computedLineHeight(view());
1309 return style()->computedLineHeight(view());
1312 LayoutUnit RenderInline::baselinePosition(FontBaseline baselineType, bool firstLine, LineDirectionMode direction, LinePositionMode linePositionMode) const
1314 const FontMetrics& fontMetrics = style(firstLine)->fontMetrics();
1315 return fontMetrics.ascent(baselineType) + (lineHeight(firstLine, direction, linePositionMode) - fontMetrics.height()) / 2;
1318 LayoutSize RenderInline::relativePositionedInlineOffset(const RenderBox* child) const
1320 // FIXME: This function isn't right with mixed writing modes.
1322 ASSERT(isRelPositioned());
1323 if (!isRelPositioned())
1324 return LayoutSize();
1326 // When we have an enclosing relpositioned inline, we need to add in the offset of the first line
1327 // box from the rest of the content, but only in the cases where we know we're positioned
1328 // relative to the inline itself.
1330 LayoutSize logicalOffset;
1331 LayoutUnit inlinePosition;
1332 LayoutUnit blockPosition;
1333 if (firstLineBox()) {
1334 inlinePosition = roundedLayoutUnit(firstLineBox()->logicalLeft());
1335 blockPosition = firstLineBox()->logicalTop();
1337 inlinePosition = layer()->staticInlinePosition();
1338 blockPosition = layer()->staticBlockPosition();
1341 if (!child->style()->hasStaticInlinePosition(style()->isHorizontalWritingMode()))
1342 logicalOffset.setWidth(inlinePosition);
1344 // This is not terribly intuitive, but we have to match other browsers. Despite being a block display type inside
1345 // an inline, we still keep our x locked to the left of the relative positioned inline. Arguably the correct
1346 // behavior would be to go flush left to the block that contains the inline, but that isn't what other browsers
1348 else if (!child->style()->isOriginalDisplayInlineType())
1349 // Avoid adding in the left border/padding of the containing block twice. Subtract it out.
1350 logicalOffset.setWidth(inlinePosition - child->containingBlock()->borderAndPaddingLogicalLeft());
1352 if (!child->style()->hasStaticBlockPosition(style()->isHorizontalWritingMode()))
1353 logicalOffset.setHeight(blockPosition);
1355 return style()->isHorizontalWritingMode() ? logicalOffset : logicalOffset.transposedSize();
1358 void RenderInline::imageChanged(WrappedImagePtr, const IntRect*)
1363 // FIXME: We can do better.
1367 void RenderInline::addFocusRingRects(Vector<IntRect>& rects, const LayoutPoint& additionalOffset)
1369 if (!alwaysCreateLineBoxes())
1370 culledInlineAbsoluteRects(this, rects, toLayoutSize(additionalOffset));
1372 for (InlineFlowBox* curr = firstLineBox(); curr; curr = curr->nextLineBox())
1373 rects.append(enclosingIntRect(FloatRect(additionalOffset.x() + curr->x(), additionalOffset.y() + curr->y(), curr->width(), curr->height())));
1376 for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) {
1377 if (!curr->isText() && !curr->isListMarker()) {
1378 FloatPoint pos(additionalOffset);
1379 // FIXME: This doesn't work correctly with transforms.
1380 if (curr->hasLayer())
1381 pos = curr->localToAbsolute();
1382 else if (curr->isBox())
1383 pos.move(toRenderBox(curr)->x(), toRenderBox(curr)->y());
1384 curr->addFocusRingRects(rects, flooredIntPoint(pos));
1388 if (continuation()) {
1389 if (continuation()->isInline())
1390 continuation()->addFocusRingRects(rects, flooredLayoutPoint(additionalOffset + continuation()->containingBlock()->location() - containingBlock()->location()));
1392 continuation()->addFocusRingRects(rects, flooredLayoutPoint(additionalOffset + toRenderBox(continuation())->location() - containingBlock()->location()));
1396 void RenderInline::paintOutline(GraphicsContext* graphicsContext, const LayoutPoint& paintOffset)
1401 RenderStyle* styleToUse = style();
1402 if (styleToUse->outlineStyleIsAuto() || hasOutlineAnnotation()) {
1403 if (!theme()->supportsFocusRing(styleToUse)) {
1404 // Only paint the focus ring by hand if the theme isn't able to draw the focus ring.
1405 paintFocusRing(graphicsContext, paintOffset, styleToUse);
1409 if (graphicsContext->paintingDisabled())
1412 if (styleToUse->outlineStyleIsAuto() || styleToUse->outlineStyle() == BNONE)
1415 Vector<LayoutRect> rects;
1417 rects.append(LayoutRect());
1418 for (InlineFlowBox* curr = firstLineBox(); curr; curr = curr->nextLineBox()) {
1419 RootInlineBox* root = curr->root();
1420 LayoutUnit top = max<LayoutUnit>(root->lineTop(), curr->logicalTop());
1421 LayoutUnit bottom = min<LayoutUnit>(root->lineBottom(), curr->logicalBottom());
1422 rects.append(LayoutRect(curr->x(), top, curr->logicalWidth(), bottom - top));
1424 rects.append(LayoutRect());
1426 Color outlineColor = styleToUse->visitedDependentColor(CSSPropertyOutlineColor);
1427 bool useTransparencyLayer = outlineColor.hasAlpha();
1428 if (useTransparencyLayer) {
1429 graphicsContext->beginTransparencyLayer(static_cast<float>(outlineColor.alpha()) / 255);
1430 outlineColor = Color(outlineColor.red(), outlineColor.green(), outlineColor.blue());
1433 for (unsigned i = 1; i < rects.size() - 1; i++)
1434 paintOutlineForLine(graphicsContext, paintOffset, rects.at(i - 1), rects.at(i), rects.at(i + 1), outlineColor);
1436 if (useTransparencyLayer)
1437 graphicsContext->endTransparencyLayer();
1440 void RenderInline::paintOutlineForLine(GraphicsContext* graphicsContext, const LayoutPoint& paintOffset,
1441 const LayoutRect& lastline, const LayoutRect& thisline, const LayoutRect& nextline,
1442 const Color outlineColor)
1444 RenderStyle* styleToUse = style();
1445 int outlineWidth = styleToUse->outlineWidth();
1446 EBorderStyle outlineStyle = styleToUse->outlineStyle();
1448 bool antialias = shouldAntialiasLines(graphicsContext);
1450 int offset = style()->outlineOffset();
1452 LayoutRect box(LayoutPoint(paintOffset.x() + thisline.x() - offset, paintOffset.y() + thisline.y() - offset),
1453 LayoutSize(thisline.width() + offset, thisline.height() + offset));
1455 IntRect pixelSnappedBox = pixelSnappedIntRect(box);
1456 IntRect pixelSnappedLastLine = pixelSnappedIntRect(paintOffset.x() + lastline.x(), 0, lastline.width(), 0);
1457 IntRect pixelSnappedNextLine = pixelSnappedIntRect(paintOffset.x() + nextline.x(), 0, nextline.width(), 0);
1460 drawLineForBoxSide(graphicsContext,
1461 pixelSnappedBox.x() - outlineWidth,
1462 pixelSnappedBox.y() - (lastline.isEmpty() || thisline.x() < lastline.x() || (lastline.maxX() - 1) <= thisline.x() ? outlineWidth : 0),
1463 pixelSnappedBox.x(),
1464 pixelSnappedBox.maxY() + (nextline.isEmpty() || thisline.x() <= nextline.x() || (nextline.maxX() - 1) <= thisline.x() ? outlineWidth : 0),
1466 outlineColor, outlineStyle,
1467 (lastline.isEmpty() || thisline.x() < lastline.x() || (lastline.maxX() - 1) <= thisline.x() ? outlineWidth : -outlineWidth),
1468 (nextline.isEmpty() || thisline.x() <= nextline.x() || (nextline.maxX() - 1) <= thisline.x() ? outlineWidth : -outlineWidth),
1472 drawLineForBoxSide(graphicsContext,
1473 pixelSnappedBox.maxX(),
1474 pixelSnappedBox.y() - (lastline.isEmpty() || lastline.maxX() < thisline.maxX() || (thisline.maxX() - 1) <= lastline.x() ? outlineWidth : 0),
1475 pixelSnappedBox.maxX() + outlineWidth,
1476 pixelSnappedBox.maxY() + (nextline.isEmpty() || nextline.maxX() <= thisline.maxX() || (thisline.maxX() - 1) <= nextline.x() ? outlineWidth : 0),
1478 outlineColor, outlineStyle,
1479 (lastline.isEmpty() || lastline.maxX() < thisline.maxX() || (thisline.maxX() - 1) <= lastline.x() ? outlineWidth : -outlineWidth),
1480 (nextline.isEmpty() || nextline.maxX() <= thisline.maxX() || (thisline.maxX() - 1) <= nextline.x() ? outlineWidth : -outlineWidth),
1483 if (thisline.x() < lastline.x())
1484 drawLineForBoxSide(graphicsContext,
1485 pixelSnappedBox.x() - outlineWidth,
1486 pixelSnappedBox.y() - outlineWidth,
1487 min(pixelSnappedBox.maxX() + outlineWidth, (lastline.isEmpty() ? 1000000 : pixelSnappedLastLine.x())),
1488 pixelSnappedBox.y(),
1489 BSTop, outlineColor, outlineStyle,
1491 (!lastline.isEmpty() && paintOffset.x() + lastline.x() + 1 < pixelSnappedBox.maxX() + outlineWidth) ? -outlineWidth : outlineWidth,
1494 if (lastline.maxX() < thisline.maxX())
1495 drawLineForBoxSide(graphicsContext,
1496 max(lastline.isEmpty() ? -1000000 : pixelSnappedLastLine.maxX(), pixelSnappedBox.x() - outlineWidth),
1497 pixelSnappedBox.y() - outlineWidth,
1498 pixelSnappedBox.maxX() + outlineWidth,
1499 pixelSnappedBox.y(),
1500 BSTop, outlineColor, outlineStyle,
1501 (!lastline.isEmpty() && pixelSnappedBox.x() - outlineWidth < paintOffset.x() + lastline.maxX()) ? -outlineWidth : outlineWidth,
1502 outlineWidth, antialias);
1504 if (thisline.x() == thisline.maxX())
1505 drawLineForBoxSide(graphicsContext,
1506 pixelSnappedBox.x() - outlineWidth,
1507 pixelSnappedBox.y() - outlineWidth,
1508 pixelSnappedBox.maxX() + outlineWidth,
1509 pixelSnappedBox.y(),
1510 BSTop, outlineColor, outlineStyle,
1516 if (thisline.x() < nextline.x())
1517 drawLineForBoxSide(graphicsContext,
1518 pixelSnappedBox.x() - outlineWidth,
1519 pixelSnappedBox.maxY(),
1520 min(pixelSnappedBox.maxX() + outlineWidth, !nextline.isEmpty() ? pixelSnappedNextLine.x() + 1 : 1000000),
1521 pixelSnappedBox.maxY() + outlineWidth,
1522 BSBottom, outlineColor, outlineStyle,
1524 (!nextline.isEmpty() && paintOffset.x() + nextline.x() + 1 < pixelSnappedBox.maxX() + outlineWidth) ? -outlineWidth : outlineWidth,
1527 if (nextline.maxX() < thisline.maxX())
1528 drawLineForBoxSide(graphicsContext,
1529 max(!nextline.isEmpty() ? pixelSnappedNextLine.maxX() : -1000000, pixelSnappedBox.x() - outlineWidth),
1530 pixelSnappedBox.maxY(),
1531 pixelSnappedBox.maxX() + outlineWidth,
1532 pixelSnappedBox.maxY() + outlineWidth,
1533 BSBottom, outlineColor, outlineStyle,
1534 (!nextline.isEmpty() && pixelSnappedBox.x() - outlineWidth < paintOffset.x() + nextline.maxX()) ? -outlineWidth : outlineWidth,
1535 outlineWidth, antialias);
1537 if (thisline.x() == thisline.maxX())
1538 drawLineForBoxSide(graphicsContext,
1539 pixelSnappedBox.x() - outlineWidth,
1540 pixelSnappedBox.maxY(),
1541 pixelSnappedBox.maxX() + outlineWidth,
1542 pixelSnappedBox.maxY() + outlineWidth,
1543 BSBottom, outlineColor, outlineStyle,
1549 #if ENABLE(DASHBOARD_SUPPORT)
1550 void RenderInline::addDashboardRegions(Vector<DashboardRegionValue>& regions)
1552 // Convert the style regions to absolute coordinates.
1553 if (style()->visibility() != VISIBLE)
1556 const Vector<StyleDashboardRegion>& styleRegions = style()->dashboardRegions();
1557 unsigned i, count = styleRegions.size();
1558 for (i = 0; i < count; i++) {
1559 StyleDashboardRegion styleRegion = styleRegions[i];
1561 LayoutRect linesBoundingBox = this->linesBoundingBox();
1562 LayoutUnit w = linesBoundingBox.width();
1563 LayoutUnit h = linesBoundingBox.height();
1565 DashboardRegionValue region;
1566 region.label = styleRegion.label;
1567 region.bounds = LayoutRect(linesBoundingBox.x() + styleRegion.offset.left().value(),
1568 linesBoundingBox.y() + styleRegion.offset.top().value(),
1569 w - styleRegion.offset.left().value() - styleRegion.offset.right().value(),
1570 h - styleRegion.offset.top().value() - styleRegion.offset.bottom().value());
1571 region.type = styleRegion.type;
1573 RenderObject* container = containingBlock();
1577 region.clip = region.bounds;
1578 container->computeAbsoluteRepaintRect(region.clip);
1579 if (region.clip.height() < 0) {
1580 region.clip.setHeight(0);
1581 region.clip.setWidth(0);
1584 FloatPoint absPos = container->localToAbsolute();
1585 region.bounds.setX(absPos.x() + region.bounds.x());
1586 region.bounds.setY(absPos.y() + region.bounds.y());
1588 regions.append(region);
1593 } // namespace WebCore