2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3 * (C) 1999 Antti Koivisto (koivisto@kde.org)
4 * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
16 * You should have received a copy of the GNU Library General Public License
17 * along with this library; see the file COPYING.LIB. If not, write to
18 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301, USA.
24 #include "core/rendering/RenderInline.h"
26 #include "core/dom/FullscreenElementStack.h"
27 #include "core/dom/StyleEngine.h"
28 #include "core/page/Chrome.h"
29 #include "core/page/Page.h"
30 #include "core/rendering/GraphicsContextAnnotator.h"
31 #include "core/rendering/HitTestResult.h"
32 #include "core/rendering/InlineTextBox.h"
33 #include "core/rendering/RenderBlock.h"
34 #include "core/rendering/RenderFlowThread.h"
35 #include "core/rendering/RenderFullScreen.h"
36 #include "core/rendering/RenderGeometryMap.h"
37 #include "core/rendering/RenderLayer.h"
38 #include "core/rendering/RenderTheme.h"
39 #include "core/rendering/RenderView.h"
40 #include "core/rendering/style/StyleInheritedData.h"
41 #include "platform/geometry/FloatQuad.h"
42 #include "platform/geometry/TransformState.h"
43 #include "platform/graphics/GraphicsContext.h"
47 struct SameSizeAsRenderInline : public RenderBoxModelObject {
48 virtual ~SameSizeAsRenderInline() { }
49 RenderObjectChildList m_children;
50 RenderLineBoxList m_lineBoxes;
53 COMPILE_ASSERT(sizeof(RenderInline) == sizeof(SameSizeAsRenderInline), RenderInline_should_stay_small);
55 RenderInline::RenderInline(Element* element)
56 : RenderBoxModelObject(element)
58 setChildrenInline(true);
61 void RenderInline::trace(Visitor* visitor)
63 visitor->trace(m_children);
64 RenderBoxModelObject::trace(visitor);
67 RenderInline* RenderInline::createAnonymous(Document* document)
69 RenderInline* renderer = new RenderInline(0);
70 renderer->setDocumentForAnonymous(document);
74 void RenderInline::willBeDestroyed()
77 // Make sure we do not retain "this" in the continuation outline table map of our containing blocks.
78 if (parent() && style()->visibility() == VISIBLE && hasOutline()) {
79 bool containingBlockPaintsContinuationOutline = continuation() || isInlineElementContinuation();
80 if (containingBlockPaintsContinuationOutline) {
81 if (RenderBlock* cb = containingBlock()) {
82 if (RenderBlock* cbCb = cb->containingBlock())
83 ASSERT(!cbCb->paintsContinuationOutline(this));
89 // Make sure to destroy anonymous children first while they are still connected to the rest of the tree, so that they will
90 // properly dirty line boxes that they are removed from. Effects that do :before/:after only on hover could crash otherwise.
91 children()->destroyLeftoverChildren();
93 // Destroy our continuation before anything other than anonymous children.
94 // The reason we don't destroy it before anonymous children is that they may
95 // have continuations of their own that are anonymous children of our continuation.
96 RenderBoxModelObject* continuation = this->continuation();
98 continuation->destroy();
102 if (!documentBeingDestroyed()) {
103 if (firstLineBox()) {
104 // We can't wait for RenderBoxModelObject::destroy to clear the selection,
105 // because by then we will have nuked the line boxes.
106 // FIXME: The FrameSelection should be responsible for this when it
107 // is notified of DOM mutations.
108 if (isSelectionBorder())
109 view()->clearSelection();
111 // If line boxes are contained inside a root, that means we're an inline.
112 // In that case, we need to remove all the line boxes so that the parent
113 // lines aren't pointing to deleted children. If the first line box does
114 // not have a parent that means they are either already disconnected or
115 // root lines that can just be destroyed without disconnecting.
116 if (firstLineBox()->parent()) {
117 for (InlineFlowBox* box = firstLineBox(); box; box = box->nextLineBox())
121 parent()->dirtyLinesFromChangedChild(this);
124 m_lineBoxes.deleteLineBoxes();
126 RenderBoxModelObject::willBeDestroyed();
129 RenderInline* RenderInline::inlineElementContinuation() const
131 RenderBoxModelObject* continuation = this->continuation();
132 if (!continuation || continuation->isInline())
133 return toRenderInline(continuation);
134 return toRenderBlock(continuation)->inlineElementContinuation();
137 void RenderInline::updateFromStyle()
139 RenderBoxModelObject::updateFromStyle();
141 // FIXME: Is this still needed. Was needed for run-ins, since run-in is considered a block display type.
144 // FIXME: Support transforms and reflections on inline flows someday.
145 setHasTransform(false);
146 setHasReflection(false);
149 static RenderObject* inFlowPositionedInlineAncestor(RenderObject* p)
151 while (p && p->isRenderInline()) {
152 if (p->isRelPositioned())
159 static void updateStyleOfAnonymousBlockContinuations(RenderObject* block, const RenderStyle* newStyle, const RenderStyle* oldStyle)
161 for (;block && block->isAnonymousBlock(); block = block->nextSibling()) {
162 if (!toRenderBlock(block)->isAnonymousBlockContinuation())
165 RenderInline* cont = toRenderBlock(block)->inlineElementContinuation();
166 RefPtr<RenderStyle> blockStyle = RenderStyle::createAnonymousStyleWithDisplay(block->style(), BLOCK);
168 if (!block->style()->isOutlineEquivalent(newStyle)) {
169 blockStyle->setOutlineWidth(newStyle->outlineWidth());
170 blockStyle->setOutlineStyle(newStyle->outlineStyle());
171 blockStyle->setOutlineOffset(newStyle->outlineOffset());
172 blockStyle->setOutlineColor(block->resolveColor(newStyle, CSSPropertyOutlineColor));
173 blockStyle->setOutlineStyleIsAuto(newStyle->outlineStyleIsAuto());
174 block->setStyle(blockStyle);
177 if (block->style()->position() != newStyle->position()) {
178 // If we are no longer in-flow positioned but our descendant block(s) still have an in-flow positioned ancestor then
179 // their containing anonymous block should keep its in-flow positioning.
180 if (oldStyle->hasInFlowPosition() && inFlowPositionedInlineAncestor(cont))
182 blockStyle->setPosition(newStyle->position());
183 block->setStyle(blockStyle);
188 void RenderInline::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
190 RenderBoxModelObject::styleDidChange(diff, oldStyle);
192 // Ensure that all of the split inlines pick up the new style. We
193 // only do this if we're an inline, since we don't want to propagate
194 // a block's style to the other inlines.
195 // e.g., <font>foo <h4>goo</h4> moo</font>. The <font> inlines before
196 // and after the block share the same style, but the block doesn't
197 // need to pass its style on to anyone else.
198 RenderStyle* newStyle = style();
199 RenderInline* continuation = inlineElementContinuation();
200 for (RenderInline* currCont = continuation; currCont; currCont = currCont->inlineElementContinuation()) {
201 RenderBoxModelObject* nextCont = currCont->continuation();
202 currCont->setContinuation(0);
203 currCont->setStyle(newStyle);
204 currCont->setContinuation(nextCont);
207 // If an inline's in-flow positioning has changed then any descendant blocks will need to change their in-flow positioning accordingly.
208 // Do this by updating the position of the descendant blocks' containing anonymous blocks - there may be more than one.
209 if (continuation && oldStyle
210 && (!newStyle->isOutlineEquivalent(oldStyle)
211 || (newStyle->position() != oldStyle->position() && (newStyle->hasInFlowPosition() || oldStyle->hasInFlowPosition())))) {
212 // If any descendant blocks exist then they will be in the next anonymous block and its siblings.
213 RenderObject* block = containingBlock()->nextSibling();
214 if (block && block->isAnonymousBlock())
215 updateStyleOfAnonymousBlockContinuations(block, newStyle, oldStyle);
218 if (!alwaysCreateLineBoxes()) {
219 bool alwaysCreateLineBoxesNew = hasSelfPaintingLayer() || hasBoxDecorationBackground() || newStyle->hasPadding() || newStyle->hasMargin() || hasOutline();
220 if (oldStyle && alwaysCreateLineBoxesNew) {
221 dirtyLineBoxes(false);
222 setNeedsLayoutAndFullPaintInvalidation();
224 setAlwaysCreateLineBoxes(alwaysCreateLineBoxesNew);
228 void RenderInline::updateAlwaysCreateLineBoxes(bool fullLayout)
230 // Once we have been tainted once, just assume it will happen again. This way effects like hover highlighting that change the
231 // background color will only cause a layout on the first rollover.
232 if (alwaysCreateLineBoxes())
235 RenderStyle* parentStyle = parent()->style();
236 RenderInline* parentRenderInline = parent()->isRenderInline() ? toRenderInline(parent()) : 0;
237 bool checkFonts = document().inNoQuirksMode();
238 bool alwaysCreateLineBoxesNew = (parentRenderInline && parentRenderInline->alwaysCreateLineBoxes())
239 || (parentRenderInline && parentStyle->verticalAlign() != BASELINE)
240 || style()->verticalAlign() != BASELINE
241 || style()->textEmphasisMark() != TextEmphasisMarkNone
242 || (checkFonts && (!parentStyle->font().fontMetrics().hasIdenticalAscentDescentAndLineGap(style()->font().fontMetrics())
243 || parentStyle->lineHeight() != style()->lineHeight()));
245 if (!alwaysCreateLineBoxesNew && checkFonts && document().styleEngine()->usesFirstLineRules()) {
246 // Have to check the first line style as well.
247 parentStyle = parent()->style(true);
248 RenderStyle* childStyle = style(true);
249 alwaysCreateLineBoxesNew = !parentStyle->font().fontMetrics().hasIdenticalAscentDescentAndLineGap(childStyle->font().fontMetrics())
250 || childStyle->verticalAlign() != BASELINE
251 || parentStyle->lineHeight() != childStyle->lineHeight();
254 if (alwaysCreateLineBoxesNew) {
256 dirtyLineBoxes(false);
257 setAlwaysCreateLineBoxes();
261 LayoutRect RenderInline::localCaretRect(InlineBox* inlineBox, int, LayoutUnit* extraWidthToEndOfLine)
264 // This condition is possible if the RenderInline is at an editing boundary,
265 // i.e. the VisiblePosition is:
266 // <RenderInline editingBoundary=true>|<RenderText> </RenderText></RenderInline>
267 // FIXME: need to figure out how to make this return a valid rect, note that
268 // there are no line boxes created in the above case.
272 ASSERT_UNUSED(inlineBox, !inlineBox);
274 if (extraWidthToEndOfLine)
275 *extraWidthToEndOfLine = 0;
277 LayoutRect caretRect = localCaretRectForEmptyElement(borderAndPaddingWidth(), 0);
279 if (InlineBox* firstBox = firstLineBox())
280 caretRect.moveBy(roundedLayoutPoint(firstBox->topLeft()));
285 void RenderInline::addChild(RenderObject* newChild, RenderObject* beforeChild)
288 return addChildToContinuation(newChild, beforeChild);
289 return addChildIgnoringContinuation(newChild, beforeChild);
292 static RenderBoxModelObject* nextContinuation(RenderObject* renderer)
294 if (renderer->isInline() && !renderer->isReplaced())
295 return toRenderInline(renderer)->continuation();
296 return toRenderBlock(renderer)->inlineElementContinuation();
299 RenderBoxModelObject* RenderInline::continuationBefore(RenderObject* beforeChild)
301 if (beforeChild && beforeChild->parent() == this)
304 RenderBoxModelObject* curr = nextContinuation(this);
305 RenderBoxModelObject* nextToLast = this;
306 RenderBoxModelObject* last = this;
308 if (beforeChild && beforeChild->parent() == curr) {
309 if (curr->slowFirstChild() == beforeChild)
316 curr = nextContinuation(curr);
319 if (!beforeChild && !last->slowFirstChild())
324 void RenderInline::addChildIgnoringContinuation(RenderObject* newChild, RenderObject* beforeChild)
326 // Make sure we don't append things after :after-generated content if we have it.
327 if (!beforeChild && isAfterContent(lastChild()))
328 beforeChild = lastChild();
330 if (!newChild->isInline() && !newChild->isFloatingOrOutOfFlowPositioned()) {
331 // We are placing a block inside an inline. We have to perform a split of this
332 // inline into continuations. This involves creating an anonymous block box to hold
333 // |newChild|. We then make that block box a continuation of this inline. We take all of
334 // the children after |beforeChild| and put them in a clone of this object.
335 RefPtr<RenderStyle> newStyle = RenderStyle::createAnonymousStyleWithDisplay(style(), BLOCK);
337 // If inside an inline affected by in-flow positioning the block needs to be affected by it too.
338 // Giving the block a layer like this allows it to collect the x/y offsets from inline parents later.
339 if (RenderObject* positionedAncestor = inFlowPositionedInlineAncestor(this))
340 newStyle->setPosition(positionedAncestor->style()->position());
342 RenderBlockFlow* newBox = RenderBlockFlow::createAnonymous(&document());
343 newBox->setStyle(newStyle.release());
344 RenderBoxModelObject* oldContinuation = continuation();
345 setContinuation(newBox);
347 splitFlow(beforeChild, newBox, newChild, oldContinuation);
351 RenderBoxModelObject::addChild(newChild, beforeChild);
353 newChild->setNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation();
356 RenderInline* RenderInline::clone() const
358 RenderInline* cloneInline = new RenderInline(node());
359 cloneInline->setStyle(style());
360 cloneInline->setFlowThreadState(flowThreadState());
364 void RenderInline::splitInlines(RenderBlock* fromBlock, RenderBlock* toBlock,
365 RenderBlock* middleBlock,
366 RenderObject* beforeChild, RenderBoxModelObject* oldCont)
368 // Create a clone of this inline.
369 RenderInline* cloneInline = clone();
370 cloneInline->setContinuation(oldCont);
372 // If we're splitting the inline containing the fullscreened element,
373 // |beforeChild| may be the renderer for the fullscreened element. However,
374 // that renderer is wrapped in a RenderFullScreen, so |this| is not its
375 // parent. Since the splitting logic expects |this| to be the parent, set
376 // |beforeChild| to be the RenderFullScreen.
377 if (FullscreenElementStack* fullscreen = FullscreenElementStack::fromIfExists(document())) {
378 const Element* fullScreenElement = fullscreen->webkitCurrentFullScreenElement();
379 if (fullScreenElement && beforeChild && beforeChild->node() == fullScreenElement)
380 beforeChild = fullscreen->fullScreenRenderer();
383 // Now take all of the children from beforeChild to the end and remove
384 // them from |this| and place them in the clone.
385 RenderObject* o = beforeChild;
387 RenderObject* tmp = o;
388 o = tmp->nextSibling();
389 cloneInline->addChildIgnoringContinuation(children()->removeChildNode(this, tmp), 0);
390 tmp->setNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation();
393 // Hook |clone| up as the continuation of the middle block.
394 middleBlock->setContinuation(cloneInline);
396 // We have been reparented and are now under the fromBlock. We need
397 // to walk up our inline parent chain until we hit the containing block.
398 // Once we hit the containing block we're done.
399 RenderBoxModelObject* curr = toRenderBoxModelObject(parent());
400 RenderBoxModelObject* currChild = this;
402 // FIXME: Because splitting is O(n^2) as tags nest pathologically, we cap the depth at which we're willing to clone.
403 // There will eventually be a better approach to this problem that will let us nest to a much
404 // greater depth (see bugzilla bug 13430) but for now we have a limit. This *will* result in
405 // incorrect rendering, but the alternative is to hang forever.
406 unsigned splitDepth = 1;
407 const unsigned cMaxSplitDepth = 200;
408 while (curr && curr != fromBlock) {
409 ASSERT(curr->isRenderInline());
410 if (splitDepth < cMaxSplitDepth) {
411 // Create a new clone.
412 RenderInline* cloneChild = cloneInline;
413 cloneInline = toRenderInline(curr)->clone();
415 // Insert our child clone as the first child.
416 cloneInline->addChildIgnoringContinuation(cloneChild, 0);
418 // Hook the clone up as a continuation of |curr|.
419 RenderInline* inlineCurr = toRenderInline(curr);
420 oldCont = inlineCurr->continuation();
421 inlineCurr->setContinuation(cloneInline);
422 cloneInline->setContinuation(oldCont);
424 // Now we need to take all of the children starting from the first child
425 // *after* currChild and append them all to the clone.
426 o = currChild->nextSibling();
428 RenderObject* tmp = o;
429 o = tmp->nextSibling();
430 cloneInline->addChildIgnoringContinuation(inlineCurr->children()->removeChildNode(curr, tmp), 0);
431 tmp->setNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation();
435 // Keep walking up the chain.
437 curr = toRenderBoxModelObject(curr->parent());
441 // Now we are at the block level. We need to put the clone into the toBlock.
442 toBlock->children()->appendChildNode(toBlock, cloneInline);
444 // Now take all the children after currChild and remove them from the fromBlock
445 // and put them in the toBlock.
446 o = currChild->nextSibling();
448 RenderObject* tmp = o;
449 o = tmp->nextSibling();
450 toBlock->children()->appendChildNode(toBlock, fromBlock->children()->removeChildNode(fromBlock, tmp));
454 void RenderInline::splitFlow(RenderObject* beforeChild, RenderBlock* newBlockBox,
455 RenderObject* newChild, RenderBoxModelObject* oldCont)
457 RenderBlock* pre = 0;
458 RenderBlock* block = containingBlock();
460 // Delete our line boxes before we do the inline split into continuations.
461 block->deleteLineBoxTree();
463 bool madeNewBeforeBlock = false;
464 if (block->isAnonymousBlock() && (!block->parent() || !block->parent()->createsAnonymousWrapper())) {
465 // We can reuse this block and make it the preBlock of the next continuation.
467 pre->removePositionedObjects(0);
468 if (pre->isRenderBlockFlow())
469 toRenderBlockFlow(pre)->removeFloatingObjects();
470 block = block->containingBlock();
472 // No anonymous block available for use. Make one.
473 pre = block->createAnonymousBlock();
474 madeNewBeforeBlock = true;
477 RenderBlock* post = toRenderBlock(pre->createAnonymousBoxWithSameTypeAs(block));
479 RenderObject* boxFirst = madeNewBeforeBlock ? block->firstChild() : pre->nextSibling();
480 if (madeNewBeforeBlock)
481 block->children()->insertChildNode(block, pre, boxFirst);
482 block->children()->insertChildNode(block, newBlockBox, boxFirst);
483 block->children()->insertChildNode(block, post, boxFirst);
484 block->setChildrenInline(false);
486 if (madeNewBeforeBlock) {
487 RenderObject* o = boxFirst;
489 RenderObject* no = o;
490 o = no->nextSibling();
491 pre->children()->appendChildNode(pre, block->children()->removeChildNode(block, no));
492 no->setNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation();
496 splitInlines(pre, post, newBlockBox, beforeChild, oldCont);
498 // We already know the newBlockBox isn't going to contain inline kids, so avoid wasting
499 // time in makeChildrenNonInline by just setting this explicitly up front.
500 newBlockBox->setChildrenInline(false);
502 newBlockBox->addChild(newChild);
504 // Always just do a full layout in order to ensure that line boxes (especially wrappers for images)
505 // get deleted properly. Because objects moves from the pre block into the post block, we want to
506 // make new line boxes instead of leaving the old line boxes around.
507 pre->setNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation();
508 block->setNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation();
509 post->setNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation();
512 void RenderInline::addChildToContinuation(RenderObject* newChild, RenderObject* beforeChild)
514 RenderBoxModelObject* flow = continuationBefore(beforeChild);
515 ASSERT(!beforeChild || beforeChild->parent()->isRenderBlock() || beforeChild->parent()->isRenderInline());
516 RenderBoxModelObject* beforeChildParent = 0;
518 beforeChildParent = toRenderBoxModelObject(beforeChild->parent());
520 RenderBoxModelObject* cont = nextContinuation(flow);
522 beforeChildParent = cont;
524 beforeChildParent = flow;
527 if (newChild->isFloatingOrOutOfFlowPositioned())
528 return beforeChildParent->addChildIgnoringContinuation(newChild, beforeChild);
530 // A continuation always consists of two potential candidates: an inline or an anonymous
531 // block box holding block children.
532 bool childInline = newChild->isInline();
533 bool bcpInline = beforeChildParent->isInline();
534 bool flowInline = flow->isInline();
536 if (flow == beforeChildParent)
537 return flow->addChildIgnoringContinuation(newChild, beforeChild);
539 // The goal here is to match up if we can, so that we can coalesce and create the
540 // minimal # of continuations needed for the inline.
541 if (childInline == bcpInline || (beforeChild && beforeChild->isInline()))
542 return beforeChildParent->addChildIgnoringContinuation(newChild, beforeChild);
543 if (flowInline == childInline)
544 return flow->addChildIgnoringContinuation(newChild, 0); // Just treat like an append.
545 return beforeChildParent->addChildIgnoringContinuation(newChild, beforeChild);
549 void RenderInline::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
551 ANNOTATE_GRAPHICS_CONTEXT(paintInfo, this);
552 m_lineBoxes.paint(this, paintInfo, paintOffset);
555 template<typename GeneratorContext>
556 void RenderInline::generateLineBoxRects(GeneratorContext& yield) const
558 if (!alwaysCreateLineBoxes())
559 generateCulledLineBoxRects(yield, this);
560 else if (InlineFlowBox* curr = firstLineBox()) {
561 for (; curr; curr = curr->nextLineBox())
562 yield(FloatRect(curr->topLeft(), curr->size()));
567 template<typename GeneratorContext>
568 void RenderInline::generateCulledLineBoxRects(GeneratorContext& yield, const RenderInline* container) const
570 if (!culledInlineFirstLineBox()) {
575 bool isHorizontal = style()->isHorizontalWritingMode();
577 for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) {
578 if (curr->isFloatingOrOutOfFlowPositioned())
581 // We want to get the margin box in the inline direction, and then use our font ascent/descent in the block
582 // direction (aligned to the root box's baseline).
584 RenderBox* currBox = toRenderBox(curr);
585 if (currBox->inlineBoxWrapper()) {
586 RootInlineBox& rootBox = currBox->inlineBoxWrapper()->root();
587 int logicalTop = rootBox.logicalTop() + (rootBox.renderer().style(rootBox.isFirstLineStyle())->font().fontMetrics().ascent() - container->style(rootBox.isFirstLineStyle())->font().fontMetrics().ascent());
588 int logicalHeight = container->style(rootBox.isFirstLineStyle())->font().fontMetrics().height();
590 yield(FloatRect(currBox->inlineBoxWrapper()->x() - currBox->marginLeft(), logicalTop, (currBox->width() + currBox->marginWidth()).toFloat(), logicalHeight));
592 yield(FloatRect(logicalTop, currBox->inlineBoxWrapper()->y() - currBox->marginTop(), logicalHeight, (currBox->height() + currBox->marginHeight()).toFloat()));
594 } else if (curr->isRenderInline()) {
595 // If the child doesn't need line boxes either, then we can recur.
596 RenderInline* currInline = toRenderInline(curr);
597 if (!currInline->alwaysCreateLineBoxes())
598 currInline->generateCulledLineBoxRects(yield, container);
600 for (InlineFlowBox* childLine = currInline->firstLineBox(); childLine; childLine = childLine->nextLineBox()) {
601 RootInlineBox& rootBox = childLine->root();
602 int logicalTop = rootBox.logicalTop() + (rootBox.renderer().style(rootBox.isFirstLineStyle())->font().fontMetrics().ascent() - container->style(rootBox.isFirstLineStyle())->font().fontMetrics().ascent());
603 int logicalHeight = container->style(rootBox.isFirstLineStyle())->font().fontMetrics().height();
605 yield(FloatRect(childLine->x() - childLine->marginLogicalLeft(),
607 childLine->logicalWidth() + childLine->marginLogicalLeft() + childLine->marginLogicalRight(),
610 yield(FloatRect(logicalTop,
611 childLine->y() - childLine->marginLogicalLeft(),
613 childLine->logicalWidth() + childLine->marginLogicalLeft() + childLine->marginLogicalRight()));
616 } else if (curr->isText()) {
617 RenderText* currText = toRenderText(curr);
618 for (InlineTextBox* childText = currText->firstTextBox(); childText; childText = childText->nextTextBox()) {
619 RootInlineBox& rootBox = childText->root();
620 int logicalTop = rootBox.logicalTop() + (rootBox.renderer().style(rootBox.isFirstLineStyle())->font().fontMetrics().ascent() - container->style(rootBox.isFirstLineStyle())->font().fontMetrics().ascent());
621 int logicalHeight = container->style(rootBox.isFirstLineStyle())->font().fontMetrics().height();
623 yield(FloatRect(childText->x(), logicalTop, childText->logicalWidth(), logicalHeight));
625 yield(FloatRect(logicalTop, childText->y(), logicalHeight, childText->logicalWidth()));
633 class AbsoluteRectsGeneratorContext {
635 AbsoluteRectsGeneratorContext(Vector<IntRect>& rects, const LayoutPoint& accumulatedOffset)
637 , m_accumulatedOffset(accumulatedOffset) { }
639 void operator()(const FloatRect& rect)
641 IntRect intRect = enclosingIntRect(rect);
642 intRect.move(m_accumulatedOffset.x(), m_accumulatedOffset.y());
643 m_rects.append(intRect);
646 Vector<IntRect>& m_rects;
647 const LayoutPoint& m_accumulatedOffset;
650 } // unnamed namespace
652 void RenderInline::absoluteRects(Vector<IntRect>& rects, const LayoutPoint& accumulatedOffset) const
654 AbsoluteRectsGeneratorContext context(rects, accumulatedOffset);
655 generateLineBoxRects(context);
657 if (continuation()) {
658 if (continuation()->isBox()) {
659 RenderBox* box = toRenderBox(continuation());
660 continuation()->absoluteRects(rects, toLayoutPoint(accumulatedOffset - containingBlock()->location() + box->locationOffset()));
662 continuation()->absoluteRects(rects, toLayoutPoint(accumulatedOffset - containingBlock()->location()));
669 class AbsoluteQuadsGeneratorContext {
671 AbsoluteQuadsGeneratorContext(const RenderInline* renderer, Vector<FloatQuad>& quads)
675 m_geometryMap.pushMappingsToAncestor(renderer, 0);
678 void operator()(const FloatRect& rect)
680 m_quads.append(m_geometryMap.absoluteRect(rect));
683 Vector<FloatQuad>& m_quads;
684 RenderGeometryMap m_geometryMap;
687 } // unnamed namespace
689 void RenderInline::absoluteQuads(Vector<FloatQuad>& quads, bool* wasFixed) const
691 AbsoluteQuadsGeneratorContext context(this, quads);
692 generateLineBoxRects(context);
695 continuation()->absoluteQuads(quads, wasFixed);
698 LayoutUnit RenderInline::offsetLeft() const
701 if (InlineBox* firstBox = firstLineBoxIncludingCulling())
702 topLeft = flooredLayoutPoint(firstBox->topLeft());
703 return adjustedPositionRelativeToOffsetParent(topLeft).x();
706 LayoutUnit RenderInline::offsetTop() const
709 if (InlineBox* firstBox = firstLineBoxIncludingCulling())
710 topLeft = flooredLayoutPoint(firstBox->topLeft());
711 return adjustedPositionRelativeToOffsetParent(topLeft).y();
714 static LayoutUnit computeMargin(const RenderInline* renderer, const Length& margin)
718 if (margin.isFixed())
719 return margin.value();
720 if (margin.isPercent())
721 return minimumValueForLength(margin, std::max<LayoutUnit>(0, renderer->containingBlock()->availableLogicalWidth()));
725 LayoutUnit RenderInline::marginLeft() const
727 return computeMargin(this, style()->marginLeft());
730 LayoutUnit RenderInline::marginRight() const
732 return computeMargin(this, style()->marginRight());
735 LayoutUnit RenderInline::marginTop() const
737 return computeMargin(this, style()->marginTop());
740 LayoutUnit RenderInline::marginBottom() const
742 return computeMargin(this, style()->marginBottom());
745 LayoutUnit RenderInline::marginStart(const RenderStyle* otherStyle) const
747 return computeMargin(this, style()->marginStartUsing(otherStyle ? otherStyle : style()));
750 LayoutUnit RenderInline::marginEnd(const RenderStyle* otherStyle) const
752 return computeMargin(this, style()->marginEndUsing(otherStyle ? otherStyle : style()));
755 LayoutUnit RenderInline::marginBefore(const RenderStyle* otherStyle) const
757 return computeMargin(this, style()->marginBeforeUsing(otherStyle ? otherStyle : style()));
760 LayoutUnit RenderInline::marginAfter(const RenderStyle* otherStyle) const
762 return computeMargin(this, style()->marginAfterUsing(otherStyle ? otherStyle : style()));
765 const char* RenderInline::renderName() const
767 if (isRelPositioned())
768 return "RenderInline (relative positioned)";
769 // FIXME: Temporary hack while the new generated content system is being implemented.
770 if (isPseudoElement())
771 return "RenderInline (generated)";
773 return "RenderInline (generated)";
774 return "RenderInline";
777 bool RenderInline::nodeAtPoint(const HitTestRequest& request, HitTestResult& result,
778 const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction hitTestAction)
780 return m_lineBoxes.hitTest(this, request, result, locationInContainer, accumulatedOffset, hitTestAction);
785 class HitTestCulledInlinesGeneratorContext {
787 HitTestCulledInlinesGeneratorContext(Region& region, const HitTestLocation& location) : m_intersected(false), m_region(region), m_location(location) { }
788 void operator()(const FloatRect& rect)
790 m_intersected = m_intersected || m_location.intersects(rect);
791 m_region.unite(enclosingIntRect(rect));
793 bool intersected() const { return m_intersected; }
797 const HitTestLocation& m_location;
800 } // unnamed namespace
802 bool RenderInline::hitTestCulledInline(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset)
804 ASSERT(result.isRectBasedTest() && !alwaysCreateLineBoxes());
805 if (!visibleToHitTestRequest(request))
808 HitTestLocation tmpLocation(locationInContainer, -toLayoutSize(accumulatedOffset));
811 HitTestCulledInlinesGeneratorContext context(regionResult, tmpLocation);
812 generateCulledLineBoxRects(context, this);
814 if (context.intersected()) {
815 updateHitTestResult(result, tmpLocation.point());
816 // We can not use addNodeToRectBasedTestResult to determine if we fully enclose the hit-test area
817 // because it can only handle rectangular targets.
818 result.addNodeToRectBasedTestResult(node(), request, locationInContainer);
819 return regionResult.contains(tmpLocation.boundingBox());
824 PositionWithAffinity RenderInline::positionForPoint(const LayoutPoint& point)
826 // FIXME: Does not deal with relative positioned inlines (should it?)
827 RenderBlock* cb = containingBlock();
828 if (firstLineBox()) {
829 // This inline actually has a line box. We must have clicked in the border/padding of one of these boxes. We
830 // should try to find a result by asking our containing block.
831 return cb->positionForPoint(point);
834 // Translate the coords from the pre-anonymous block to the post-anonymous block.
835 LayoutPoint parentBlockPoint = cb->location() + point;
836 RenderBoxModelObject* c = continuation();
838 RenderBox* contBlock = c->isInline() ? c->containingBlock() : toRenderBlock(c);
839 if (c->isInline() || c->slowFirstChild())
840 return c->positionForPoint(parentBlockPoint - contBlock->locationOffset());
841 c = toRenderBlock(c)->inlineElementContinuation();
844 return RenderBoxModelObject::positionForPoint(point);
849 class LinesBoundingBoxGeneratorContext {
851 LinesBoundingBoxGeneratorContext(FloatRect& rect) : m_rect(rect) { }
852 void operator()(const FloatRect& rect)
854 m_rect.uniteIfNonZero(rect);
860 } // unnamed namespace
862 IntRect RenderInline::linesBoundingBox() const
864 if (!alwaysCreateLineBoxes()) {
865 ASSERT(!firstLineBox());
866 FloatRect floatResult;
867 LinesBoundingBoxGeneratorContext context(floatResult);
868 generateCulledLineBoxRects(context, this);
869 return enclosingIntRect(floatResult);
874 // 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
875 // 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
876 // builds and help us someday figure out why. We also put in a redundant check of lastLineBox() to avoid the crash for now.
877 ASSERT(!firstLineBox() == !lastLineBox()); // Either both are null or both exist.
878 if (firstLineBox() && lastLineBox()) {
879 // Return the width of the minimal left side and the maximal right side.
880 float logicalLeftSide = 0;
881 float logicalRightSide = 0;
882 for (InlineFlowBox* curr = firstLineBox(); curr; curr = curr->nextLineBox()) {
883 if (curr == firstLineBox() || curr->logicalLeft() < logicalLeftSide)
884 logicalLeftSide = curr->logicalLeft();
885 if (curr == firstLineBox() || curr->logicalRight() > logicalRightSide)
886 logicalRightSide = curr->logicalRight();
889 bool isHorizontal = style()->isHorizontalWritingMode();
891 float x = isHorizontal ? logicalLeftSide : firstLineBox()->x();
892 float y = isHorizontal ? firstLineBox()->y() : logicalLeftSide;
893 float width = isHorizontal ? logicalRightSide - logicalLeftSide : lastLineBox()->logicalBottom() - x;
894 float height = isHorizontal ? lastLineBox()->logicalBottom() - y : logicalRightSide - logicalLeftSide;
895 result = enclosingIntRect(FloatRect(x, y, width, height));
901 InlineBox* RenderInline::culledInlineFirstLineBox() const
903 for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) {
904 if (curr->isFloatingOrOutOfFlowPositioned())
907 // We want to get the margin box in the inline direction, and then use our font ascent/descent in the block
908 // direction (aligned to the root box's baseline).
910 return toRenderBox(curr)->inlineBoxWrapper();
911 if (curr->isRenderInline()) {
912 RenderInline* currInline = toRenderInline(curr);
913 InlineBox* result = currInline->firstLineBoxIncludingCulling();
916 } else if (curr->isText()) {
917 RenderText* currText = toRenderText(curr);
918 if (currText->firstTextBox())
919 return currText->firstTextBox();
925 InlineBox* RenderInline::culledInlineLastLineBox() const
927 for (RenderObject* curr = lastChild(); curr; curr = curr->previousSibling()) {
928 if (curr->isFloatingOrOutOfFlowPositioned())
931 // We want to get the margin box in the inline direction, and then use our font ascent/descent in the block
932 // direction (aligned to the root box's baseline).
934 return toRenderBox(curr)->inlineBoxWrapper();
935 if (curr->isRenderInline()) {
936 RenderInline* currInline = toRenderInline(curr);
937 InlineBox* result = currInline->lastLineBoxIncludingCulling();
940 } else if (curr->isText()) {
941 RenderText* currText = toRenderText(curr);
942 if (currText->lastTextBox())
943 return currText->lastTextBox();
949 LayoutRect RenderInline::culledInlineVisualOverflowBoundingBox() const
951 FloatRect floatResult;
952 LinesBoundingBoxGeneratorContext context(floatResult);
953 generateCulledLineBoxRects(context, this);
954 LayoutRect result(enclosingLayoutRect(floatResult));
955 bool isHorizontal = style()->isHorizontalWritingMode();
956 for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) {
957 if (curr->isFloatingOrOutOfFlowPositioned())
960 // For overflow we just have to propagate by hand and recompute it all.
962 RenderBox* currBox = toRenderBox(curr);
963 if (!currBox->hasSelfPaintingLayer() && currBox->inlineBoxWrapper()) {
964 LayoutRect logicalRect = currBox->logicalVisualOverflowRectForPropagation(style());
966 logicalRect.moveBy(currBox->location());
967 result.uniteIfNonZero(logicalRect);
969 logicalRect.moveBy(currBox->location());
970 result.uniteIfNonZero(logicalRect.transposedRect());
973 } else if (curr->isRenderInline()) {
974 // If the child doesn't need line boxes either, then we can recur.
975 RenderInline* currInline = toRenderInline(curr);
976 if (!currInline->alwaysCreateLineBoxes())
977 result.uniteIfNonZero(currInline->culledInlineVisualOverflowBoundingBox());
978 else if (!currInline->hasSelfPaintingLayer())
979 result.uniteIfNonZero(currInline->linesVisualOverflowBoundingBox());
980 } else if (curr->isText()) {
981 // FIXME; Overflow from text boxes is lost. We will need to cache this information in
983 RenderText* currText = toRenderText(curr);
984 result.uniteIfNonZero(currText->linesVisualOverflowBoundingBox());
990 LayoutRect RenderInline::linesVisualOverflowBoundingBox() const
992 if (!alwaysCreateLineBoxes())
993 return culledInlineVisualOverflowBoundingBox();
995 if (!firstLineBox() || !lastLineBox())
998 // Return the width of the minimal left side and the maximal right side.
999 LayoutUnit logicalLeftSide = LayoutUnit::max();
1000 LayoutUnit logicalRightSide = LayoutUnit::min();
1001 for (InlineFlowBox* curr = firstLineBox(); curr; curr = curr->nextLineBox()) {
1002 logicalLeftSide = std::min(logicalLeftSide, curr->logicalLeftVisualOverflow());
1003 logicalRightSide = std::max(logicalRightSide, curr->logicalRightVisualOverflow());
1006 RootInlineBox& firstRootBox = firstLineBox()->root();
1007 RootInlineBox& lastRootBox = lastLineBox()->root();
1009 LayoutUnit logicalTop = firstLineBox()->logicalTopVisualOverflow(firstRootBox.lineTop());
1010 LayoutUnit logicalWidth = logicalRightSide - logicalLeftSide;
1011 LayoutUnit logicalHeight = lastLineBox()->logicalBottomVisualOverflow(lastRootBox.lineBottom()) - logicalTop;
1013 LayoutRect rect(logicalLeftSide, logicalTop, logicalWidth, logicalHeight);
1014 if (!style()->isHorizontalWritingMode())
1015 rect = rect.transposedRect();
1019 LayoutRect RenderInline::clippedOverflowRectForPaintInvalidation(const RenderLayerModelObject* paintInvalidationContainer, const PaintInvalidationState* paintInvalidationState) const
1021 if ((!firstLineBoxIncludingCulling() && !continuation()) || style()->visibility() != VISIBLE)
1022 return LayoutRect();
1024 LayoutRect repaintRect(linesVisualOverflowBoundingBox());
1025 bool hitRepaintContainer = false;
1027 // We need to add in the in-flow position offsets of any inlines (including us) up to our
1028 // containing block.
1029 RenderBlock* cb = containingBlock();
1030 for (const RenderObject* inlineFlow = this; inlineFlow && inlineFlow->isRenderInline() && inlineFlow != cb;
1031 inlineFlow = inlineFlow->parent()) {
1032 if (inlineFlow == paintInvalidationContainer) {
1033 hitRepaintContainer = true;
1036 if (inlineFlow->style()->hasInFlowPosition() && inlineFlow->hasLayer())
1037 repaintRect.move(toRenderInline(inlineFlow)->layer()->offsetForInFlowPosition());
1040 LayoutUnit outlineSize = style()->outlineSize();
1041 repaintRect.inflate(outlineSize);
1043 if (hitRepaintContainer || !cb)
1046 if (cb->hasColumns())
1047 cb->adjustRectForColumns(repaintRect);
1049 if (cb->hasOverflowClip())
1050 cb->applyCachedClipAndScrollOffsetForRepaint(repaintRect);
1052 // FIXME: Passing paintInvalidationState directly to mapRectToPaintInvalidationBacking causes incorrect invalidations.
1053 // Should avoid slowRectMapping by properly adjusting paintInvalidationState. crbug.com/402994.
1054 ForceHorriblySlowRectMapping slowRectMapping(paintInvalidationState);
1055 cb->mapRectToPaintInvalidationBacking(paintInvalidationContainer, repaintRect, IsNotFixedPosition, paintInvalidationState);
1058 for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) {
1059 if (!curr->isText())
1060 repaintRect.unite(curr->rectWithOutlineForPaintInvalidation(paintInvalidationContainer, outlineSize));
1063 if (continuation() && !continuation()->isInline() && continuation()->parent())
1064 repaintRect.unite(continuation()->rectWithOutlineForPaintInvalidation(paintInvalidationContainer, outlineSize));
1070 LayoutRect RenderInline::rectWithOutlineForPaintInvalidation(const RenderLayerModelObject* paintInvalidationContainer, LayoutUnit outlineWidth, const PaintInvalidationState* paintInvalidationState) const
1072 LayoutRect r(RenderBoxModelObject::rectWithOutlineForPaintInvalidation(paintInvalidationContainer, outlineWidth, paintInvalidationState));
1073 for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) {
1074 if (!curr->isText())
1075 r.unite(curr->rectWithOutlineForPaintInvalidation(paintInvalidationContainer, outlineWidth, paintInvalidationState));
1080 void RenderInline::mapRectToPaintInvalidationBacking(const RenderLayerModelObject* paintInvalidationContainer, LayoutRect& rect, ViewportConstrainedPosition, const PaintInvalidationState* paintInvalidationState) const
1082 if (paintInvalidationState && paintInvalidationState->canMapToContainer(paintInvalidationContainer)) {
1083 if (style()->hasInFlowPosition() && layer())
1084 rect.move(layer()->offsetForInFlowPosition());
1085 rect.move(paintInvalidationState->paintOffset());
1086 if (paintInvalidationState->isClipped())
1087 rect.intersect(paintInvalidationState->clipRect());
1091 if (paintInvalidationContainer == this)
1094 bool containerSkipped;
1095 RenderObject* o = container(paintInvalidationContainer, &containerSkipped);
1099 LayoutPoint topLeft = rect.location();
1101 if (o->isRenderBlockFlow() && !style()->hasOutOfFlowPosition()) {
1102 RenderBlock* cb = toRenderBlock(o);
1103 if (cb->hasColumns()) {
1104 LayoutRect repaintRect(topLeft, rect.size());
1105 cb->adjustRectForColumns(repaintRect);
1106 topLeft = repaintRect.location();
1111 if (style()->hasInFlowPosition() && layer()) {
1112 // Apply the in-flow position offset when invalidating a rectangle. The layer
1113 // is translated, but the render box isn't, so we need to do this to get the
1114 // right dirty rect. Since this is called from RenderObject::setStyle, the relative position
1115 // flag on the RenderObject has been cleared, so use the one on the style().
1116 topLeft += layer()->offsetForInFlowPosition();
1119 // FIXME: We ignore the lightweight clipping rect that controls use, since if |o| is in mid-layout,
1120 // its controlClipRect will be wrong. For overflow clip we use the values cached by the layer.
1121 rect.setLocation(topLeft);
1122 if (o->hasOverflowClip()) {
1123 RenderBox* containerBox = toRenderBox(o);
1124 containerBox->applyCachedClipAndScrollOffsetForRepaint(rect);
1129 if (containerSkipped) {
1130 // If the paintInvalidationContainer is below o, then we need to map the rect into paintInvalidationContainer's coordinates.
1131 LayoutSize containerOffset = paintInvalidationContainer->offsetFromAncestorContainer(o);
1132 rect.move(-containerOffset);
1136 o->mapRectToPaintInvalidationBacking(paintInvalidationContainer, rect, IsNotFixedPosition, paintInvalidationState);
1139 LayoutSize RenderInline::offsetFromContainer(const RenderObject* container, const LayoutPoint& point, bool* offsetDependsOnPoint) const
1141 ASSERT(container == this->container());
1144 if (isRelPositioned())
1145 offset += offsetForInFlowPosition();
1147 offset += container->columnOffset(point);
1149 if (container->hasOverflowClip())
1150 offset -= toRenderBox(container)->scrolledContentOffset();
1152 if (offsetDependsOnPoint) {
1153 *offsetDependsOnPoint = container->hasColumns()
1154 || (container->isBox() && container->style()->isFlippedBlocksWritingMode())
1155 || container->isRenderFlowThread();
1161 void RenderInline::mapLocalToContainer(const RenderLayerModelObject* repaintContainer, TransformState& transformState, MapCoordinatesFlags mode, bool* wasFixed, const PaintInvalidationState* paintInvalidationState) const
1163 if (repaintContainer == this)
1166 if (paintInvalidationState && paintInvalidationState->canMapToContainer(repaintContainer)) {
1167 LayoutSize offset = paintInvalidationState->paintOffset();
1168 if (style()->hasInFlowPosition() && layer())
1169 offset += layer()->offsetForInFlowPosition();
1170 transformState.move(offset);
1174 bool containerSkipped;
1175 RenderObject* o = container(repaintContainer, &containerSkipped);
1179 if (mode & ApplyContainerFlip && o->isBox()) {
1180 if (o->style()->isFlippedBlocksWritingMode()) {
1181 IntPoint centerPoint = roundedIntPoint(transformState.mappedPoint());
1182 transformState.move(toRenderBox(o)->flipForWritingModeIncludingColumns(centerPoint) - centerPoint);
1184 mode &= ~ApplyContainerFlip;
1187 LayoutSize containerOffset = offsetFromContainer(o, roundedLayoutPoint(transformState.mappedPoint()));
1189 bool preserve3D = mode & UseTransforms && (o->style()->preserves3D() || style()->preserves3D());
1190 if (mode & UseTransforms && shouldUseTransformFromContainer(o)) {
1191 TransformationMatrix t;
1192 getTransformFromContainer(o, containerOffset, t);
1193 transformState.applyTransform(t, preserve3D ? TransformState::AccumulateTransform : TransformState::FlattenTransform);
1195 transformState.move(containerOffset.width(), containerOffset.height(), preserve3D ? TransformState::AccumulateTransform : TransformState::FlattenTransform);
1197 if (containerSkipped) {
1198 // There can't be a transform between repaintContainer and o, because transforms create containers, so it should be safe
1199 // to just subtract the delta between the repaintContainer and o.
1200 LayoutSize containerOffset = repaintContainer->offsetFromAncestorContainer(o);
1201 transformState.move(-containerOffset.width(), -containerOffset.height(), preserve3D ? TransformState::AccumulateTransform : TransformState::FlattenTransform);
1205 o->mapLocalToContainer(repaintContainer, transformState, mode, wasFixed, paintInvalidationState);
1208 void RenderInline::updateDragState(bool dragOn)
1210 RenderBoxModelObject::updateDragState(dragOn);
1212 continuation()->updateDragState(dragOn);
1215 void RenderInline::childBecameNonInline(RenderObject* child)
1217 // We have to split the parent flow.
1218 RenderBlock* newBox = containingBlock()->createAnonymousBlock();
1219 RenderBoxModelObject* oldContinuation = continuation();
1220 setContinuation(newBox);
1221 RenderObject* beforeChild = child->nextSibling();
1222 children()->removeChildNode(this, child);
1223 splitFlow(beforeChild, newBox, child, oldContinuation);
1226 void RenderInline::updateHitTestResult(HitTestResult& result, const LayoutPoint& point)
1228 if (result.innerNode())
1232 LayoutPoint localPoint(point);
1234 if (isInlineElementContinuation()) {
1235 // We're in the continuation of a split inline. Adjust our local point to be in the coordinate space
1236 // of the principal renderer's containing block. This will end up being the innerNonSharedNode.
1237 RenderBlock* firstBlock = n->renderer()->containingBlock();
1239 // Get our containing block.
1240 RenderBox* block = containingBlock();
1241 localPoint.moveBy(block->location() - firstBlock->locationOffset());
1244 result.setInnerNode(n);
1245 if (!result.innerNonSharedNode())
1246 result.setInnerNonSharedNode(n);
1247 result.setLocalPoint(localPoint);
1251 void RenderInline::dirtyLineBoxes(bool fullLayout)
1254 m_lineBoxes.deleteLineBoxes();
1258 if (!alwaysCreateLineBoxes()) {
1259 // We have to grovel into our children in order to dirty the appropriate lines.
1260 for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) {
1261 if (curr->isFloatingOrOutOfFlowPositioned())
1263 if (curr->isBox() && !curr->needsLayout()) {
1264 RenderBox* currBox = toRenderBox(curr);
1265 if (currBox->inlineBoxWrapper())
1266 currBox->inlineBoxWrapper()->root().markDirty();
1267 } else if (!curr->selfNeedsLayout()) {
1268 if (curr->isRenderInline()) {
1269 RenderInline* currInline = toRenderInline(curr);
1270 for (InlineFlowBox* childLine = currInline->firstLineBox(); childLine; childLine = childLine->nextLineBox())
1271 childLine->root().markDirty();
1272 } else if (curr->isText()) {
1273 RenderText* currText = toRenderText(curr);
1274 for (InlineTextBox* childText = currText->firstTextBox(); childText; childText = childText->nextTextBox())
1275 childText->root().markDirty();
1280 m_lineBoxes.dirtyLineBoxes();
1283 void RenderInline::deleteLineBoxTree()
1285 m_lineBoxes.deleteLineBoxTree();
1288 InlineFlowBox* RenderInline::createInlineFlowBox()
1290 return new 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().styleEngine()->usesFirstLineRules()) {
1304 RenderStyle* s = style(firstLine);
1306 return s->computedLineHeight();
1309 return style()->computedLineHeight();
1312 int RenderInline::baselinePosition(FontBaseline baselineType, bool firstLine, LineDirectionMode direction, LinePositionMode linePositionMode) const
1314 ASSERT(linePositionMode == PositionOnContainingLine);
1315 const FontMetrics& fontMetrics = style(firstLine)->fontMetrics();
1316 return fontMetrics.ascent(baselineType) + (lineHeight(firstLine, direction, linePositionMode) - fontMetrics.height()) / 2;
1319 LayoutSize RenderInline::offsetForInFlowPositionedInline(const RenderBox& child) const
1321 // FIXME: This function isn't right with mixed writing modes.
1323 ASSERT(isRelPositioned());
1324 if (!isRelPositioned())
1325 return LayoutSize();
1327 // When we have an enclosing relpositioned inline, we need to add in the offset of the first line
1328 // box from the rest of the content, but only in the cases where we know we're positioned
1329 // relative to the inline itself.
1331 LayoutSize logicalOffset;
1332 LayoutUnit inlinePosition;
1333 LayoutUnit blockPosition;
1334 if (firstLineBox()) {
1335 inlinePosition = LayoutUnit::fromFloatRound(firstLineBox()->logicalLeft());
1336 blockPosition = firstLineBox()->logicalTop();
1338 inlinePosition = layer()->staticInlinePosition();
1339 blockPosition = layer()->staticBlockPosition();
1342 if (!child.style()->hasStaticInlinePosition(style()->isHorizontalWritingMode()))
1343 logicalOffset.setWidth(inlinePosition);
1345 // This is not terribly intuitive, but we have to match other browsers. Despite being a block display type inside
1346 // an inline, we still keep our x locked to the left of the relative positioned inline. Arguably the correct
1347 // behavior would be to go flush left to the block that contains the inline, but that isn't what other browsers
1349 else if (!child.style()->isOriginalDisplayInlineType())
1350 // Avoid adding in the left border/padding of the containing block twice. Subtract it out.
1351 logicalOffset.setWidth(inlinePosition - child.containingBlock()->borderAndPaddingLogicalLeft());
1353 if (!child.style()->hasStaticBlockPosition(style()->isHorizontalWritingMode()))
1354 logicalOffset.setHeight(blockPosition);
1356 return style()->isHorizontalWritingMode() ? logicalOffset : logicalOffset.transposedSize();
1359 void RenderInline::imageChanged(WrappedImagePtr, const IntRect*)
1364 // FIXME: We can do better.
1365 paintInvalidationForWholeRenderer();
1368 void RenderInline::addFocusRingRects(Vector<IntRect>& rects, const LayoutPoint& additionalOffset, const RenderLayerModelObject* paintContainer) const
1370 AbsoluteRectsGeneratorContext context(rects, additionalOffset);
1371 generateLineBoxRects(context);
1373 addChildFocusRingRects(rects, additionalOffset, paintContainer);
1375 if (continuation()) {
1376 // If the continuation doesn't paint into the same container, let its repaint container handle it.
1377 if (paintContainer != continuation()->containerForPaintInvalidation())
1379 if (continuation()->isInline())
1380 continuation()->addFocusRingRects(rects, flooredLayoutPoint(additionalOffset + continuation()->containingBlock()->location() - containingBlock()->location()), paintContainer);
1382 continuation()->addFocusRingRects(rects, flooredLayoutPoint(additionalOffset + toRenderBox(continuation())->location() - containingBlock()->location()), paintContainer);
1388 class AbsoluteLayoutRectsGeneratorContext {
1390 AbsoluteLayoutRectsGeneratorContext(Vector<LayoutRect>& rects, const LayoutPoint& accumulatedOffset)
1392 , m_accumulatedOffset(accumulatedOffset) { }
1394 void operator()(const FloatRect& rect)
1396 LayoutRect layoutRect(rect);
1397 layoutRect.move(m_accumulatedOffset.x(), m_accumulatedOffset.y());
1398 m_rects.append(layoutRect);
1401 Vector<LayoutRect>& m_rects;
1402 const LayoutPoint& m_accumulatedOffset;
1407 void RenderInline::computeSelfHitTestRects(Vector<LayoutRect>& rects, const LayoutPoint& layerOffset) const
1409 AbsoluteLayoutRectsGeneratorContext context(rects, layerOffset);
1410 generateLineBoxRects(context);
1413 void RenderInline::paintOutline(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
1418 RenderStyle* styleToUse = style();
1419 if (styleToUse->outlineStyleIsAuto() || hasOutlineAnnotation()) {
1420 if (RenderTheme::theme().shouldDrawDefaultFocusRing(this)) {
1421 // Only paint the focus ring by hand if the theme isn't able to draw the focus ring.
1422 paintFocusRing(paintInfo, paintOffset, styleToUse);
1426 if (styleToUse->outlineStyleIsAuto() || styleToUse->outlineStyle() == BNONE)
1429 Vector<LayoutRect> rects;
1431 rects.append(LayoutRect());
1432 for (InlineFlowBox* curr = firstLineBox(); curr; curr = curr->nextLineBox()) {
1433 RootInlineBox& root = curr->root();
1434 LayoutUnit top = std::max<LayoutUnit>(root.lineTop(), curr->logicalTop());
1435 LayoutUnit bottom = std::min<LayoutUnit>(root.lineBottom(), curr->logicalBottom());
1436 rects.append(LayoutRect(curr->x(), top, curr->logicalWidth(), bottom - top));
1438 rects.append(LayoutRect());
1440 Color outlineColor = resolveColor(styleToUse, CSSPropertyOutlineColor);
1441 bool useTransparencyLayer = outlineColor.hasAlpha();
1443 GraphicsContext* graphicsContext = paintInfo.context;
1444 if (useTransparencyLayer) {
1445 graphicsContext->beginTransparencyLayer(static_cast<float>(outlineColor.alpha()) / 255);
1446 outlineColor = Color(outlineColor.red(), outlineColor.green(), outlineColor.blue());
1449 for (unsigned i = 1; i < rects.size() - 1; i++)
1450 paintOutlineForLine(graphicsContext, paintOffset, rects.at(i - 1), rects.at(i), rects.at(i + 1), outlineColor);
1452 if (useTransparencyLayer)
1453 graphicsContext->endLayer();
1456 void RenderInline::paintOutlineForLine(GraphicsContext* graphicsContext, const LayoutPoint& paintOffset,
1457 const LayoutRect& lastline, const LayoutRect& thisline, const LayoutRect& nextline,
1458 const Color outlineColor)
1460 RenderStyle* styleToUse = style();
1461 int outlineWidth = styleToUse->outlineWidth();
1462 EBorderStyle outlineStyle = styleToUse->outlineStyle();
1464 bool antialias = shouldAntialiasLines(graphicsContext);
1466 int offset = style()->outlineOffset();
1468 LayoutRect box(LayoutPoint(paintOffset.x() + thisline.x() - offset, paintOffset.y() + thisline.y() - offset),
1469 LayoutSize(thisline.width() + offset, thisline.height() + offset));
1471 IntRect pixelSnappedBox = pixelSnappedIntRect(box);
1472 if (pixelSnappedBox.width() < 0 || pixelSnappedBox.height() < 0)
1474 IntRect pixelSnappedLastLine = pixelSnappedIntRect(paintOffset.x() + lastline.x(), 0, lastline.width(), 0);
1475 IntRect pixelSnappedNextLine = pixelSnappedIntRect(paintOffset.x() + nextline.x(), 0, nextline.width(), 0);
1478 drawLineForBoxSide(graphicsContext,
1479 pixelSnappedBox.x() - outlineWidth,
1480 pixelSnappedBox.y() - (lastline.isEmpty() || thisline.x() < lastline.x() || (lastline.maxX() - 1) <= thisline.x() ? outlineWidth : 0),
1481 pixelSnappedBox.x(),
1482 pixelSnappedBox.maxY() + (nextline.isEmpty() || thisline.x() <= nextline.x() || (nextline.maxX() - 1) <= thisline.x() ? outlineWidth : 0),
1484 outlineColor, outlineStyle,
1485 (lastline.isEmpty() || thisline.x() < lastline.x() || (lastline.maxX() - 1) <= thisline.x() ? outlineWidth : -outlineWidth),
1486 (nextline.isEmpty() || thisline.x() <= nextline.x() || (nextline.maxX() - 1) <= thisline.x() ? outlineWidth : -outlineWidth),
1490 drawLineForBoxSide(graphicsContext,
1491 pixelSnappedBox.maxX(),
1492 pixelSnappedBox.y() - (lastline.isEmpty() || lastline.maxX() < thisline.maxX() || (thisline.maxX() - 1) <= lastline.x() ? outlineWidth : 0),
1493 pixelSnappedBox.maxX() + outlineWidth,
1494 pixelSnappedBox.maxY() + (nextline.isEmpty() || nextline.maxX() <= thisline.maxX() || (thisline.maxX() - 1) <= nextline.x() ? outlineWidth : 0),
1496 outlineColor, outlineStyle,
1497 (lastline.isEmpty() || lastline.maxX() < thisline.maxX() || (thisline.maxX() - 1) <= lastline.x() ? outlineWidth : -outlineWidth),
1498 (nextline.isEmpty() || nextline.maxX() <= thisline.maxX() || (thisline.maxX() - 1) <= nextline.x() ? outlineWidth : -outlineWidth),
1501 if (thisline.x() < lastline.x())
1502 drawLineForBoxSide(graphicsContext,
1503 pixelSnappedBox.x() - outlineWidth,
1504 pixelSnappedBox.y() - outlineWidth,
1505 std::min(pixelSnappedBox.maxX() + outlineWidth, (lastline.isEmpty() ? 1000000 : pixelSnappedLastLine.x())),
1506 pixelSnappedBox.y(),
1507 BSTop, outlineColor, outlineStyle,
1509 (!lastline.isEmpty() && paintOffset.x() + lastline.x() + 1 < pixelSnappedBox.maxX() + outlineWidth) ? -outlineWidth : outlineWidth,
1512 if (lastline.maxX() < thisline.maxX())
1513 drawLineForBoxSide(graphicsContext,
1514 std::max(lastline.isEmpty() ? -1000000 : pixelSnappedLastLine.maxX(), pixelSnappedBox.x() - outlineWidth),
1515 pixelSnappedBox.y() - outlineWidth,
1516 pixelSnappedBox.maxX() + outlineWidth,
1517 pixelSnappedBox.y(),
1518 BSTop, outlineColor, outlineStyle,
1519 (!lastline.isEmpty() && pixelSnappedBox.x() - outlineWidth < paintOffset.x() + lastline.maxX()) ? -outlineWidth : outlineWidth,
1520 outlineWidth, antialias);
1522 if (thisline.x() == thisline.maxX())
1523 drawLineForBoxSide(graphicsContext,
1524 pixelSnappedBox.x() - outlineWidth,
1525 pixelSnappedBox.y() - outlineWidth,
1526 pixelSnappedBox.maxX() + outlineWidth,
1527 pixelSnappedBox.y(),
1528 BSTop, outlineColor, outlineStyle,
1534 if (thisline.x() < nextline.x())
1535 drawLineForBoxSide(graphicsContext,
1536 pixelSnappedBox.x() - outlineWidth,
1537 pixelSnappedBox.maxY(),
1538 std::min(pixelSnappedBox.maxX() + outlineWidth, !nextline.isEmpty() ? pixelSnappedNextLine.x() + 1 : 1000000),
1539 pixelSnappedBox.maxY() + outlineWidth,
1540 BSBottom, outlineColor, outlineStyle,
1542 (!nextline.isEmpty() && paintOffset.x() + nextline.x() + 1 < pixelSnappedBox.maxX() + outlineWidth) ? -outlineWidth : outlineWidth,
1545 if (nextline.maxX() < thisline.maxX())
1546 drawLineForBoxSide(graphicsContext,
1547 std::max(!nextline.isEmpty() ? pixelSnappedNextLine.maxX() : -1000000, pixelSnappedBox.x() - outlineWidth),
1548 pixelSnappedBox.maxY(),
1549 pixelSnappedBox.maxX() + outlineWidth,
1550 pixelSnappedBox.maxY() + outlineWidth,
1551 BSBottom, outlineColor, outlineStyle,
1552 (!nextline.isEmpty() && pixelSnappedBox.x() - outlineWidth < paintOffset.x() + nextline.maxX()) ? -outlineWidth : outlineWidth,
1553 outlineWidth, antialias);
1555 if (thisline.x() == thisline.maxX())
1556 drawLineForBoxSide(graphicsContext,
1557 pixelSnappedBox.x() - outlineWidth,
1558 pixelSnappedBox.maxY(),
1559 pixelSnappedBox.maxX() + outlineWidth,
1560 pixelSnappedBox.maxY() + outlineWidth,
1561 BSBottom, outlineColor, outlineStyle,
1567 void RenderInline::addAnnotatedRegions(Vector<AnnotatedRegionValue>& regions)
1569 // Convert the style regions to absolute coordinates.
1570 if (style()->visibility() != VISIBLE)
1573 if (style()->getDraggableRegionMode() == DraggableRegionNone)
1576 AnnotatedRegionValue region;
1577 region.draggable = style()->getDraggableRegionMode() == DraggableRegionDrag;
1578 region.bounds = linesBoundingBox();
1580 RenderObject* container = containingBlock();
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);
1591 } // namespace blink