Clean up the difference between painting focus rings and adding PDF annotations
[WebKit-https.git] / Source / WebCore / rendering / RenderInline.cpp
1 /*
2  * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3  *           (C) 1999 Antti Koivisto (koivisto@kde.org)
4  * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
5  *
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.
10  *
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.
15  *
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.
20  *
21  */
22
23 #include "config.h"
24 #include "RenderInline.h"
25
26 #include "Chrome.h"
27 #include "FloatQuad.h"
28 #include "GraphicsContext.h"
29 #include "HitTestResult.h"
30 #include "InlineElementBox.h"
31 #include "InlineTextBox.h"
32 #include "Page.h"
33 #include "RenderBlock.h"
34 #include "RenderFullScreen.h"
35 #include "RenderGeometryMap.h"
36 #include "RenderIterator.h"
37 #include "RenderLayer.h"
38 #include "RenderLineBreak.h"
39 #include "RenderNamedFlowThread.h"
40 #include "RenderTheme.h"
41 #include "RenderView.h"
42 #include "StyleInheritedData.h"
43 #include "TransformState.h"
44 #include "VisiblePosition.h"
45
46 #if ENABLE(DASHBOARD_SUPPORT)
47 #include "Frame.h"
48 #endif
49
50 namespace WebCore {
51
52 RenderInline::RenderInline(Element& element, PassRef<RenderStyle> style)
53     : RenderBoxModelObject(element, std::move(style), RenderInlineFlag)
54 {
55     setChildrenInline(true);
56 }
57
58 RenderInline::RenderInline(Document& document, PassRef<RenderStyle> style)
59     : RenderBoxModelObject(document, std::move(style), RenderInlineFlag)
60 {
61     setChildrenInline(true);
62 }
63
64 void RenderInline::willBeDestroyed()
65 {
66 #if !ASSERT_DISABLED
67     // Make sure we do not retain "this" in the continuation outline table map of our containing blocks.
68     if (parent() && style().visibility() == VISIBLE && hasOutline()) {
69         bool containingBlockPaintsContinuationOutline = continuation() || isInlineElementContinuation();
70         if (containingBlockPaintsContinuationOutline) {
71             if (RenderBlock* cb = containingBlock()) {
72                 if (RenderBlock* cbCb = cb->containingBlock())
73                     ASSERT(!cbCb->paintsContinuationOutline(this));
74             }
75         }
76     }
77 #endif
78
79     // Make sure to destroy anonymous children first while they are still connected to the rest of the tree, so that they will
80     // properly dirty line boxes that they are removed from.  Effects that do :before/:after only on hover could crash otherwise.
81     destroyLeftoverChildren();
82
83     // Destroy our continuation before anything other than anonymous children.
84     // The reason we don't destroy it before anonymous children is that they may
85     // have continuations of their own that are anonymous children of our continuation.
86     RenderBoxModelObject* continuation = this->continuation();
87     if (continuation) {
88         continuation->destroy();
89         setContinuation(0);
90     }
91     
92     if (!documentBeingDestroyed()) {
93         if (firstLineBox()) {
94             // We can't wait for RenderBoxModelObject::destroy to clear the selection,
95             // because by then we will have nuked the line boxes.
96             // FIXME: The FrameSelection should be responsible for this when it
97             // is notified of DOM mutations.
98             if (isSelectionBorder())
99                 view().clearSelection();
100
101             // If line boxes are contained inside a root, that means we're an inline.
102             // In that case, we need to remove all the line boxes so that the parent
103             // lines aren't pointing to deleted children. If the first line box does
104             // not have a parent that means they are either already disconnected or
105             // root lines that can just be destroyed without disconnecting.
106             if (firstLineBox()->parent()) {
107                 for (auto box = firstLineBox(); box; box = box->nextLineBox())
108                     box->removeFromParent();
109             }
110         } else if (parent()) 
111             parent()->dirtyLinesFromChangedChild(this);
112     }
113
114     m_lineBoxes.deleteLineBoxes();
115
116     RenderBoxModelObject::willBeDestroyed();
117 }
118
119 RenderInline* RenderInline::inlineElementContinuation() const
120 {
121     RenderBoxModelObject* continuation = this->continuation();
122     if (!continuation)
123         return nullptr;
124
125     if (continuation->isRenderInline())
126         return toRenderInline(continuation);
127
128     return continuation->isRenderBlock() ? toRenderBlock(continuation)->inlineElementContinuation() : nullptr;
129 }
130
131 void RenderInline::updateFromStyle()
132 {
133     RenderBoxModelObject::updateFromStyle();
134
135     // FIXME: Support transforms and reflections on inline flows someday.
136     setHasTransform(false);
137     setHasReflection(false);    
138 }
139
140 static RenderElement* inFlowPositionedInlineAncestor(RenderElement* p)
141 {
142     while (p && p->isRenderInline()) {
143         if (p->isInFlowPositioned())
144             return p;
145         p = p->parent();
146     }
147     return 0;
148 }
149
150 static void updateStyleOfAnonymousBlockContinuations(RenderBox* box, const RenderStyle* newStyle, const RenderStyle* oldStyle)
151 {
152     for (;box && box->isAnonymousBlock(); box = box->nextSiblingBox()) {
153         if (box->style().position() == newStyle->position())
154             continue;
155         
156         if (!box->isRenderBlock())
157             continue;
158
159         RenderBlock* block = toRenderBlock(box);
160         if (!block->isAnonymousBlockContinuation())
161             continue;
162         
163         // If we are no longer in-flow positioned but our descendant block(s) still have an in-flow positioned ancestor then
164         // their containing anonymous block should keep its in-flow positioning. 
165         RenderInline* cont = block->inlineElementContinuation();
166         if (oldStyle->hasInFlowPosition() && inFlowPositionedInlineAncestor(cont))
167             continue;
168         auto blockStyle = RenderStyle::createAnonymousStyleWithDisplay(&block->style(), BLOCK);
169         blockStyle.get().setPosition(newStyle->position());
170         block->setStyle(std::move(blockStyle));
171     }
172 }
173
174 void RenderInline::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
175 {
176     RenderBoxModelObject::styleDidChange(diff, oldStyle);
177
178     // Ensure that all of the split inlines pick up the new style. We
179     // only do this if we're an inline, since we don't want to propagate
180     // a block's style to the other inlines.
181     // e.g., <font>foo <h4>goo</h4> moo</font>.  The <font> inlines before
182     // and after the block share the same style, but the block doesn't
183     // need to pass its style on to anyone else.
184     RenderStyle& newStyle = style();
185     RenderInline* continuation = inlineElementContinuation();
186     for (RenderInline* currCont = continuation; currCont; currCont = currCont->inlineElementContinuation()) {
187         RenderBoxModelObject* nextCont = currCont->continuation();
188         currCont->setContinuation(0);
189         currCont->setStyle(newStyle);
190         currCont->setContinuation(nextCont);
191     }
192
193     // If an inline's in-flow positioning has changed then any descendant blocks will need to change their in-flow positioning accordingly.
194     // Do this by updating the position of the descendant blocks' containing anonymous blocks - there may be more than one.
195     if (continuation && oldStyle && newStyle.position() != oldStyle->position()
196         && (newStyle.hasInFlowPosition() || oldStyle->hasInFlowPosition())) {
197         // If any descendant blocks exist then they will be in the next anonymous block and its siblings.
198         RenderObject* block = containingBlock()->nextSibling();
199         ASSERT(block && block->isAnonymousBlock());
200         updateStyleOfAnonymousBlockContinuations(toRenderBlock(block), &newStyle, oldStyle);
201     }
202
203     if (!alwaysCreateLineBoxes()) {
204         bool alwaysCreateLineBoxes = hasSelfPaintingLayer() || hasBoxDecorations() || newStyle.hasPadding() || newStyle.hasMargin() || hasOutline();
205         if (oldStyle && alwaysCreateLineBoxes) {
206             dirtyLineBoxes(false);
207             setNeedsLayout();
208         }
209         setRenderInlineAlwaysCreatesLineBoxes(alwaysCreateLineBoxes);
210     }
211 }
212
213 void RenderInline::updateAlwaysCreateLineBoxes(bool fullLayout)
214 {
215     // Once we have been tainted once, just assume it will happen again. This way effects like hover highlighting that change the
216     // background color will only cause a layout on the first rollover.
217     if (alwaysCreateLineBoxes())
218         return;
219
220     RenderStyle* parentStyle = &parent()->style();
221     RenderInline* parentRenderInline = parent()->isRenderInline() ? toRenderInline(parent()) : 0;
222     bool checkFonts = document().inNoQuirksMode();
223     RenderFlowThread* flowThread = flowThreadContainingBlock();
224     bool alwaysCreateLineBoxes = (parentRenderInline && parentRenderInline->alwaysCreateLineBoxes())
225         || (parentRenderInline && parentStyle->verticalAlign() != BASELINE)
226         || style().verticalAlign() != BASELINE
227         || style().textEmphasisMark() != TextEmphasisMarkNone
228         || (checkFonts && (!parentStyle->font().fontMetrics().hasIdenticalAscentDescentAndLineGap(style().font().fontMetrics())
229         || parentStyle->lineHeight() != style().lineHeight()))
230         || (flowThread && flowThread->isRenderNamedFlowThread()); // FIXME: Enable the optimization once we make overflow computation for culled inlines in regions.
231
232     if (!alwaysCreateLineBoxes && checkFonts && document().styleSheetCollection().usesFirstLineRules()) {
233         // Have to check the first line style as well.
234         parentStyle = &parent()->firstLineStyle();
235         RenderStyle& childStyle = firstLineStyle();
236         alwaysCreateLineBoxes = !parentStyle->font().fontMetrics().hasIdenticalAscentDescentAndLineGap(childStyle.font().fontMetrics())
237             || childStyle.verticalAlign() != BASELINE
238             || parentStyle->lineHeight() != childStyle.lineHeight();
239     }
240
241     if (alwaysCreateLineBoxes) {
242         if (!fullLayout)
243             dirtyLineBoxes(false);
244         setAlwaysCreateLineBoxes();
245     }
246 }
247
248 LayoutRect RenderInline::localCaretRect(InlineBox* inlineBox, int, LayoutUnit* extraWidthToEndOfLine)
249 {
250     if (firstChild()) {
251         // This condition is possible if the RenderInline is at an editing boundary,
252         // i.e. the VisiblePosition is:
253         //   <RenderInline editingBoundary=true>|<RenderText> </RenderText></RenderInline>
254         // FIXME: need to figure out how to make this return a valid rect, note that
255         // there are no line boxes created in the above case.
256         return LayoutRect();
257     }
258
259     ASSERT_UNUSED(inlineBox, !inlineBox);
260
261     if (extraWidthToEndOfLine)
262         *extraWidthToEndOfLine = 0;
263
264     LayoutRect caretRect = localCaretRectForEmptyElement(horizontalBorderAndPaddingExtent(), 0);
265
266     if (InlineBox* firstBox = firstLineBox())
267         caretRect.moveBy(roundedLayoutPoint(firstBox->topLeft()));
268
269     return caretRect;
270 }
271
272 void RenderInline::addChild(RenderObject* newChild, RenderObject* beforeChild)
273 {
274     if (continuation())
275         return addChildToContinuation(newChild, beforeChild);
276     return addChildIgnoringContinuation(newChild, beforeChild);
277 }
278
279 static RenderBoxModelObject* nextContinuation(RenderObject* renderer)
280 {
281     if (renderer->isInline() && !renderer->isReplaced())
282         return toRenderInline(renderer)->continuation();
283     return toRenderBlock(renderer)->inlineElementContinuation();
284 }
285
286 RenderBoxModelObject* RenderInline::continuationBefore(RenderObject* beforeChild)
287 {
288     if (beforeChild && beforeChild->parent() == this)
289         return this;
290
291     RenderBoxModelObject* curr = nextContinuation(this);
292     RenderBoxModelObject* nextToLast = this;
293     RenderBoxModelObject* last = this;
294     while (curr) {
295         if (beforeChild && beforeChild->parent() == curr) {
296             if (curr->firstChild() == beforeChild)
297                 return last;
298             return curr;
299         }
300
301         nextToLast = last;
302         last = curr;
303         curr = nextContinuation(curr);
304     }
305
306     if (!beforeChild && !last->firstChild())
307         return nextToLast;
308     return last;
309 }
310
311 void RenderInline::addChildIgnoringContinuation(RenderObject* newChild, RenderObject* beforeChild)
312 {
313     // Make sure we don't append things after :after-generated content if we have it.
314     if (!beforeChild && isAfterContent(lastChild()))
315         beforeChild = lastChild();
316
317     if (!newChild->isInline() && !newChild->isFloatingOrOutOfFlowPositioned()) {
318         // We are placing a block inside an inline. We have to perform a split of this
319         // inline into continuations.  This involves creating an anonymous block box to hold
320         // |newChild|.  We then make that block box a continuation of this inline.  We take all of
321         // the children after |beforeChild| and put them in a clone of this object.
322         auto newStyle = RenderStyle::createAnonymousStyleWithDisplay(&style(), BLOCK);
323         
324         // If inside an inline affected by in-flow positioning the block needs to be affected by it too.
325         // Giving the block a layer like this allows it to collect the x/y offsets from inline parents later.
326         if (auto positionedAncestor = inFlowPositionedInlineAncestor(this))
327             newStyle.get().setPosition(positionedAncestor->style().position());
328
329         RenderBlock* newBox = new RenderBlockFlow(document(), std::move(newStyle));
330         newBox->initializeStyle();
331         RenderBoxModelObject* oldContinuation = continuation();
332         setContinuation(newBox);
333
334         splitFlow(beforeChild, newBox, newChild, oldContinuation);
335         return;
336     }
337
338     RenderBoxModelObject::addChild(newChild, beforeChild);
339
340     newChild->setNeedsLayoutAndPrefWidthsRecalc();
341 }
342
343 RenderPtr<RenderInline> RenderInline::clone() const
344 {
345     RenderPtr<RenderInline> cloneInline = createRenderer<RenderInline>(*element(), style());
346     cloneInline->initializeStyle();
347     cloneInline->setFlowThreadState(flowThreadState());
348     return cloneInline;
349 }
350
351 void RenderInline::splitInlines(RenderBlock* fromBlock, RenderBlock* toBlock,
352                                 RenderBlock* middleBlock,
353                                 RenderObject* beforeChild, RenderBoxModelObject* oldCont)
354 {
355     // Create a clone of this inline.
356     RenderPtr<RenderInline> cloneInline = clone();
357     cloneInline->setContinuation(oldCont);
358
359 #if ENABLE(FULLSCREEN_API)
360     // If we're splitting the inline containing the fullscreened element,
361     // |beforeChild| may be the renderer for the fullscreened element. However,
362     // that renderer is wrapped in a RenderFullScreen, so |this| is not its
363     // parent. Since the splitting logic expects |this| to be the parent, set
364     // |beforeChild| to be the RenderFullScreen.
365     const Element* fullScreenElement = document().webkitCurrentFullScreenElement();
366     if (fullScreenElement && beforeChild && beforeChild->node() == fullScreenElement)
367         beforeChild = document().fullScreenRenderer();
368 #endif
369
370     // Now take all of the children from beforeChild to the end and remove
371     // them from |this| and place them in the clone.
372     RenderObject* o = beforeChild;
373     while (o) {
374         RenderObject* tmp = o;
375         o = tmp->nextSibling();
376         removeChildInternal(*tmp, NotifyChildren);
377         cloneInline->addChildIgnoringContinuation(tmp, 0);
378         tmp->setNeedsLayoutAndPrefWidthsRecalc();
379     }
380
381     // Hook |clone| up as the continuation of the middle block.
382     middleBlock->setContinuation(cloneInline.get());
383
384     // We have been reparented and are now under the fromBlock.  We need
385     // to walk up our inline parent chain until we hit the containing block.
386     // Once we hit the containing block we're done.
387     RenderBoxModelObject* curr = toRenderBoxModelObject(parent());
388     RenderBoxModelObject* currChild = this;
389     
390     // FIXME: Because splitting is O(n^2) as tags nest pathologically, we cap the depth at which we're willing to clone.
391     // There will eventually be a better approach to this problem that will let us nest to a much
392     // greater depth (see bugzilla bug 13430) but for now we have a limit.  This *will* result in
393     // incorrect rendering, but the alternative is to hang forever.
394     unsigned splitDepth = 1;
395     const unsigned cMaxSplitDepth = 200; 
396     while (curr && curr != fromBlock) {
397         ASSERT(curr->isRenderInline());
398         if (splitDepth < cMaxSplitDepth) {
399             // Create a new clone.
400             RenderPtr<RenderInline> cloneChild = std::move(cloneInline);
401             cloneInline = toRenderInline(curr)->clone();
402
403             // Insert our child clone as the first child.
404             cloneInline->addChildIgnoringContinuation(cloneChild.leakPtr(), 0);
405
406             // Hook the clone up as a continuation of |curr|.
407             RenderInline* inlineCurr = toRenderInline(curr);
408             oldCont = inlineCurr->continuation();
409             inlineCurr->setContinuation(cloneInline.get());
410             cloneInline->setContinuation(oldCont);
411
412             // Now we need to take all of the children starting from the first child
413             // *after* currChild and append them all to the clone.
414             o = currChild->nextSibling();
415             while (o) {
416                 RenderObject* tmp = o;
417                 o = tmp->nextSibling();
418                 inlineCurr->removeChildInternal(*tmp, NotifyChildren);
419                 cloneInline->addChildIgnoringContinuation(tmp, 0);
420                 tmp->setNeedsLayoutAndPrefWidthsRecalc();
421             }
422         }
423         
424         // Keep walking up the chain.
425         currChild = curr;
426         curr = toRenderBoxModelObject(curr->parent());
427         splitDepth++;
428     }
429
430     // Now we are at the block level. We need to put the clone into the toBlock.
431     toBlock->insertChildInternal(cloneInline.leakPtr(), nullptr, NotifyChildren);
432
433     // Now take all the children after currChild and remove them from the fromBlock
434     // and put them in the toBlock.
435     o = currChild->nextSibling();
436     while (o) {
437         RenderObject* tmp = o;
438         o = tmp->nextSibling();
439         fromBlock->removeChildInternal(*tmp, NotifyChildren);
440         toBlock->insertChildInternal(tmp, nullptr, NotifyChildren);
441     }
442 }
443
444 void RenderInline::splitFlow(RenderObject* beforeChild, RenderBlock* newBlockBox,
445                              RenderObject* newChild, RenderBoxModelObject* oldCont)
446 {
447     RenderBlock* pre = 0;
448     RenderBlock* block = containingBlock();
449     
450     // Delete our line boxes before we do the inline split into continuations.
451     block->deleteLines();
452     
453     bool madeNewBeforeBlock = false;
454     if (block->isAnonymousBlock() && (!block->parent() || !block->parent()->createsAnonymousWrapper())) {
455         // We can reuse this block and make it the preBlock of the next continuation.
456         pre = block;
457         pre->removePositionedObjects(0);
458         // FIXME-BLOCKFLOW: The enclosing method should likely be switched over
459         // to only work on RenderBlockFlow, in which case this conversion can be
460         // removed.
461         if (pre->isRenderBlockFlow())
462             toRenderBlockFlow(pre)->removeFloatingObjects();
463         block = block->containingBlock();
464     } else {
465         // No anonymous block available for use.  Make one.
466         pre = block->createAnonymousBlock();
467         madeNewBeforeBlock = true;
468     }
469
470     RenderBlock* post = toRenderBlock(pre->createAnonymousBoxWithSameTypeAs(block));
471
472     RenderObject* boxFirst = madeNewBeforeBlock ? block->firstChild() : pre->nextSibling();
473     if (madeNewBeforeBlock)
474         block->insertChildInternal(pre, boxFirst, NotifyChildren);
475     block->insertChildInternal(newBlockBox, boxFirst, NotifyChildren);
476     block->insertChildInternal(post, boxFirst, NotifyChildren);
477     block->setChildrenInline(false);
478     
479     if (madeNewBeforeBlock) {
480         RenderObject* o = boxFirst;
481         while (o) {
482             RenderObject* no = o;
483             o = no->nextSibling();
484             block->removeChildInternal(*no, NotifyChildren);
485             pre->insertChildInternal(no, nullptr, NotifyChildren);
486             no->setNeedsLayoutAndPrefWidthsRecalc();
487         }
488     }
489
490     splitInlines(pre, post, newBlockBox, beforeChild, oldCont);
491
492     // We already know the newBlockBox isn't going to contain inline kids, so avoid wasting
493     // time in makeChildrenNonInline by just setting this explicitly up front.
494     newBlockBox->setChildrenInline(false);
495
496     // We delayed adding the newChild until now so that the |newBlockBox| would be fully
497     // connected, thus allowing newChild access to a renderArena should it need
498     // to wrap itself in additional boxes (e.g., table construction).
499     newBlockBox->addChild(newChild);
500
501     // Always just do a full layout in order to ensure that line boxes (especially wrappers for images)
502     // get deleted properly.  Because objects moves from the pre block into the post block, we want to
503     // make new line boxes instead of leaving the old line boxes around.
504     pre->setNeedsLayoutAndPrefWidthsRecalc();
505     block->setNeedsLayoutAndPrefWidthsRecalc();
506     post->setNeedsLayoutAndPrefWidthsRecalc();
507 }
508
509 void RenderInline::addChildToContinuation(RenderObject* newChild, RenderObject* beforeChild)
510 {
511     RenderBoxModelObject* flow = continuationBefore(beforeChild);
512     ASSERT(!beforeChild || beforeChild->parent()->isRenderBlock() || beforeChild->parent()->isRenderInline());
513     RenderBoxModelObject* beforeChildParent = 0;
514     if (beforeChild)
515         beforeChildParent = toRenderBoxModelObject(beforeChild->parent());
516     else {
517         RenderBoxModelObject* cont = nextContinuation(flow);
518         if (cont)
519             beforeChildParent = cont;
520         else
521             beforeChildParent = flow;
522     }
523
524     if (newChild->isFloatingOrOutOfFlowPositioned())
525         return beforeChildParent->addChildIgnoringContinuation(newChild, beforeChild);
526
527     // A continuation always consists of two potential candidates: an inline or an anonymous
528     // block box holding block children.
529     bool childInline = newChild->isInline();
530     bool bcpInline = beforeChildParent->isInline();
531     bool flowInline = flow->isInline();
532
533     if (flow == beforeChildParent)
534         return flow->addChildIgnoringContinuation(newChild, beforeChild);
535     else {
536         // The goal here is to match up if we can, so that we can coalesce and create the
537         // minimal # of continuations needed for the inline.
538         if (childInline == bcpInline)
539             return beforeChildParent->addChildIgnoringContinuation(newChild, beforeChild);
540         else if (flowInline == childInline)
541             return flow->addChildIgnoringContinuation(newChild, 0); // Just treat like an append.
542         else
543             return beforeChildParent->addChildIgnoringContinuation(newChild, beforeChild);
544     }
545 }
546
547 void RenderInline::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
548 {
549     m_lineBoxes.paint(this, paintInfo, paintOffset);
550 }
551
552 template<typename GeneratorContext>
553 void RenderInline::generateLineBoxRects(GeneratorContext& yield) const
554 {
555     if (!alwaysCreateLineBoxes())
556         generateCulledLineBoxRects(yield, this);
557     else if (InlineFlowBox* curr = firstLineBox()) {
558         for (; curr; curr = curr->nextLineBox())
559             yield(FloatRect(curr->topLeft(), curr->size()));
560     } else
561         yield(FloatRect());
562 }
563
564 template<typename GeneratorContext>
565 void RenderInline::generateCulledLineBoxRects(GeneratorContext& yield, const RenderInline* container) const
566 {
567     if (!culledInlineFirstLineBox()) {
568         yield(FloatRect());
569         return;
570     }
571
572     bool isHorizontal = style().isHorizontalWritingMode();
573
574     for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) {
575         if (curr->isFloatingOrOutOfFlowPositioned())
576             continue;
577             
578         // We want to get the margin box in the inline direction, and then use our font ascent/descent in the block
579         // direction (aligned to the root box's baseline).
580         if (curr->isBox()) {
581             RenderBox* currBox = toRenderBox(curr);
582             if (currBox->inlineBoxWrapper()) {
583                 const RootInlineBox& rootBox = currBox->inlineBoxWrapper()->root();
584                 const RenderStyle& containerStyle = rootBox.isFirstLine() ? container->firstLineStyle() : container->style();
585                 int logicalTop = rootBox.logicalTop() + (rootBox.lineStyle().font().fontMetrics().ascent() - containerStyle.font().fontMetrics().ascent());
586                 int logicalHeight = containerStyle.font().fontMetrics().height();
587                 if (isHorizontal)
588                     yield(FloatRect(currBox->inlineBoxWrapper()->x() - currBox->marginLeft(), logicalTop, currBox->width() + currBox->horizontalMarginExtent(), logicalHeight));
589                 else
590                     yield(FloatRect(logicalTop, currBox->inlineBoxWrapper()->y() - currBox->marginTop(), logicalHeight, currBox->height() + currBox->verticalMarginExtent()));
591             }
592         } else if (curr->isRenderInline()) {
593             // If the child doesn't need line boxes either, then we can recur.
594             RenderInline* currInline = toRenderInline(curr);
595             if (!currInline->alwaysCreateLineBoxes())
596                 currInline->generateCulledLineBoxRects(yield, container);
597             else {
598                 for (InlineFlowBox* childLine = currInline->firstLineBox(); childLine; childLine = childLine->nextLineBox()) {
599                     const RootInlineBox& rootBox = childLine->root();
600                     const RenderStyle& containerStyle = rootBox.isFirstLine() ? container->firstLineStyle() : container->style();
601                     int logicalTop = rootBox.logicalTop() + (rootBox.lineStyle().font().fontMetrics().ascent() - containerStyle.font().fontMetrics().ascent());
602                     int logicalHeight = containerStyle.fontMetrics().height();
603                     if (isHorizontal)
604                         yield(FloatRect(childLine->x() - childLine->marginLogicalLeft(),
605                             logicalTop,
606                             childLine->logicalWidth() + childLine->marginLogicalLeft() + childLine->marginLogicalRight(),
607                             logicalHeight));
608                     else
609                         yield(FloatRect(logicalTop,
610                             childLine->y() - childLine->marginLogicalLeft(),
611                             logicalHeight,
612                             childLine->logicalWidth() + childLine->marginLogicalLeft() + childLine->marginLogicalRight()));
613                 }
614             }
615         } else if (curr->isText()) {
616             RenderText* currText = toRenderText(curr);
617             for (InlineTextBox* childText = currText->firstTextBox(); childText; childText = childText->nextTextBox()) {
618                 const RootInlineBox& rootBox = childText->root();
619                 const RenderStyle& containerStyle = rootBox.isFirstLine() ? container->firstLineStyle() : container->style();
620                 int logicalTop = rootBox.logicalTop() + (rootBox.lineStyle().font().fontMetrics().ascent() - containerStyle.font().fontMetrics().ascent());
621                 int logicalHeight = containerStyle.font().fontMetrics().height();
622                 if (isHorizontal)
623                     yield(FloatRect(childText->x(), logicalTop, childText->logicalWidth(), logicalHeight));
624                 else
625                     yield(FloatRect(logicalTop, childText->y(), logicalHeight, childText->logicalWidth()));
626             }
627         } else if (curr->isLineBreak()) {
628             if (InlineBox* inlineBox = toRenderLineBreak(curr)->inlineBoxWrapper()) {
629                 // FIXME: This could use a helper to share these with text path.
630                 const RootInlineBox& rootBox = inlineBox->root();
631                 const RenderStyle& containerStyle = rootBox.isFirstLine() ? container->firstLineStyle() : container->style();
632                 int logicalTop = rootBox.logicalTop() + (rootBox.lineStyle().font().fontMetrics().ascent() - containerStyle.font().fontMetrics().ascent());
633                 int logicalHeight = containerStyle.fontMetrics().height();
634                 if (isHorizontal)
635                     yield(FloatRect(inlineBox->x(), logicalTop, inlineBox->logicalWidth(), logicalHeight));
636                 else
637                     yield(FloatRect(logicalTop, inlineBox->y(), logicalHeight, inlineBox->logicalWidth()));
638             }
639         }
640     }
641 }
642
643 namespace {
644
645 class AbsoluteRectsGeneratorContext {
646 public:
647     AbsoluteRectsGeneratorContext(Vector<IntRect>& rects, const LayoutPoint& accumulatedOffset)
648         : m_rects(rects)
649         , m_accumulatedOffset(accumulatedOffset) { }
650
651     void operator()(const FloatRect& rect)
652     {
653         IntRect intRect = enclosingIntRect(rect);
654         intRect.move(m_accumulatedOffset.x(), m_accumulatedOffset.y());
655         m_rects.append(intRect);
656     }
657 private:
658     Vector<IntRect>& m_rects;
659     const LayoutPoint& m_accumulatedOffset;
660 };
661
662 } // unnamed namespace
663
664 void RenderInline::absoluteRects(Vector<IntRect>& rects, const LayoutPoint& accumulatedOffset) const
665 {
666     AbsoluteRectsGeneratorContext context(rects, accumulatedOffset);
667     generateLineBoxRects(context);
668
669     if (RenderBoxModelObject* continuation = this->continuation()) {
670         if (continuation->isBox()) {
671             RenderBox* box = toRenderBox(continuation);
672             continuation->absoluteRects(rects, toLayoutPoint(accumulatedOffset - containingBlock()->location() + box->locationOffset()));
673         } else
674             continuation->absoluteRects(rects, toLayoutPoint(accumulatedOffset - containingBlock()->location()));
675     }
676 }
677
678
679 namespace {
680
681 class AbsoluteQuadsGeneratorContext {
682 public:
683     AbsoluteQuadsGeneratorContext(const RenderInline* renderer, Vector<FloatQuad>& quads)
684         : m_quads(quads)
685         , m_geometryMap()
686     {
687         m_geometryMap.pushMappingsToAncestor(renderer, 0);
688     }
689
690     void operator()(const FloatRect& rect)
691     {
692         m_quads.append(m_geometryMap.absoluteRect(rect));
693     }
694 private:
695     Vector<FloatQuad>& m_quads;
696     RenderGeometryMap m_geometryMap;
697 };
698
699 } // unnamed namespace
700
701 void RenderInline::absoluteQuads(Vector<FloatQuad>& quads, bool* wasFixed) const
702 {
703     AbsoluteQuadsGeneratorContext context(this, quads);
704     generateLineBoxRects(context);
705
706     if (RenderBoxModelObject* continuation = this->continuation())
707         continuation->absoluteQuads(quads, wasFixed);
708 }
709
710 #if PLATFORM(IOS)
711 void RenderInline::absoluteQuadsForSelection(Vector<FloatQuad>& quads) const
712 {
713     AbsoluteQuadsGeneratorContext context(this, quads);
714     generateLineBoxRects(context);
715 }
716 #endif
717
718 LayoutUnit RenderInline::offsetLeft() const
719 {
720     LayoutPoint topLeft;
721     if (InlineBox* firstBox = firstLineBoxIncludingCulling())
722         topLeft = flooredLayoutPoint(firstBox->topLeft());
723     return adjustedPositionRelativeToOffsetParent(topLeft).x();
724 }
725
726 LayoutUnit RenderInline::offsetTop() const
727 {
728     LayoutPoint topLeft;
729     if (InlineBox* firstBox = firstLineBoxIncludingCulling())
730         topLeft = flooredLayoutPoint(firstBox->topLeft());
731     return adjustedPositionRelativeToOffsetParent(topLeft).y();
732 }
733
734 static LayoutUnit computeMargin(const RenderInline* renderer, const Length& margin)
735 {
736     if (margin.isAuto())
737         return 0;
738     if (margin.isFixed())
739         return margin.value();
740     if (margin.isPercent())
741         return minimumValueForLength(margin, std::max<LayoutUnit>(0, renderer->containingBlock()->availableLogicalWidth()));
742     if (margin.isViewportPercentage())
743         return valueForLength(margin, 0, &renderer->view());
744     return 0;
745 }
746
747 LayoutUnit RenderInline::marginLeft() const
748 {
749     return computeMargin(this, style().marginLeft());
750 }
751
752 LayoutUnit RenderInline::marginRight() const
753 {
754     return computeMargin(this, style().marginRight());
755 }
756
757 LayoutUnit RenderInline::marginTop() const
758 {
759     return computeMargin(this, style().marginTop());
760 }
761
762 LayoutUnit RenderInline::marginBottom() const
763 {
764     return computeMargin(this, style().marginBottom());
765 }
766
767 LayoutUnit RenderInline::marginStart(const RenderStyle* otherStyle) const
768 {
769     return computeMargin(this, style().marginStartUsing(otherStyle ? otherStyle : &style()));
770 }
771
772 LayoutUnit RenderInline::marginEnd(const RenderStyle* otherStyle) const
773 {
774     return computeMargin(this, style().marginEndUsing(otherStyle ? otherStyle : &style()));
775 }
776
777 LayoutUnit RenderInline::marginBefore(const RenderStyle* otherStyle) const
778 {
779     return computeMargin(this, style().marginBeforeUsing(otherStyle ? otherStyle : &style()));
780 }
781
782 LayoutUnit RenderInline::marginAfter(const RenderStyle* otherStyle) const
783 {
784     return computeMargin(this, style().marginAfterUsing(otherStyle ? otherStyle : &style()));
785 }
786
787 const char* RenderInline::renderName() const
788 {
789     if (isRelPositioned())
790         return "RenderInline (relative positioned)";
791     if (isStickyPositioned())
792         return "RenderInline (sticky positioned)";
793     // FIXME: Temporary hack while the new generated content system is being implemented.
794     if (isPseudoElement())
795         return "RenderInline (generated)";
796     if (isAnonymous())
797         return "RenderInline (generated)";
798     return "RenderInline";
799 }
800
801 bool RenderInline::nodeAtPoint(const HitTestRequest& request, HitTestResult& result,
802                                 const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction hitTestAction)
803 {
804     return m_lineBoxes.hitTest(this, request, result, locationInContainer, accumulatedOffset, hitTestAction);
805 }
806
807 namespace {
808
809 class HitTestCulledInlinesGeneratorContext {
810 public:
811     HitTestCulledInlinesGeneratorContext(Region& region, const HitTestLocation& location) : m_intersected(false), m_region(region), m_location(location) { }
812     void operator()(const FloatRect& rect)
813     {
814         m_intersected = m_intersected || m_location.intersects(rect);
815         m_region.unite(enclosingIntRect(rect));
816     }
817     bool intersected() const { return m_intersected; }
818 private:
819     bool m_intersected;
820     Region& m_region;
821     const HitTestLocation& m_location;
822 };
823
824 } // unnamed namespace
825
826 bool RenderInline::hitTestCulledInline(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset)
827 {
828     ASSERT(result.isRectBasedTest() && !alwaysCreateLineBoxes());
829     if (!visibleToHitTesting())
830         return false;
831
832     HitTestLocation tmpLocation(locationInContainer, -toLayoutSize(accumulatedOffset));
833
834     Region regionResult;
835     HitTestCulledInlinesGeneratorContext context(regionResult, tmpLocation);
836     generateCulledLineBoxRects(context, this);
837
838     if (context.intersected()) {
839         updateHitTestResult(result, tmpLocation.point());
840         // We can not use addNodeToRectBasedTestResult to determine if we fully enclose the hit-test area
841         // because it can only handle rectangular targets.
842         result.addNodeToRectBasedTestResult(element(), request, locationInContainer);
843         return regionResult.contains(tmpLocation.boundingBox());
844     }
845     return false;
846 }
847
848 VisiblePosition RenderInline::positionForPoint(const LayoutPoint& point, const RenderRegion* region)
849 {
850     // FIXME: Does not deal with relative or sticky positioned inlines (should it?)
851     RenderBlock* cb = containingBlock();
852     if (firstLineBox()) {
853         // This inline actually has a line box.  We must have clicked in the border/padding of one of these boxes.  We
854         // should try to find a result by asking our containing block.
855         return cb->positionForPoint(point, region);
856     }
857
858     // Translate the coords from the pre-anonymous block to the post-anonymous block.
859     LayoutPoint parentBlockPoint = cb->location() + point;  
860     RenderBoxModelObject* c = continuation();
861     while (c) {
862         RenderBox* contBlock = c->isInline() ? c->containingBlock() : toRenderBlock(c);
863         if (c->isInline() || c->firstChild())
864             return c->positionForPoint(parentBlockPoint - contBlock->locationOffset(), region);
865         c = toRenderBlock(c)->inlineElementContinuation();
866     }
867     
868     return RenderBoxModelObject::positionForPoint(point, region);
869 }
870
871 namespace {
872
873 class LinesBoundingBoxGeneratorContext {
874 public:
875     LinesBoundingBoxGeneratorContext(FloatRect& rect) : m_rect(rect) { }
876     void operator()(const FloatRect& rect)
877     {
878         m_rect.uniteIfNonZero(rect);
879     }
880 private:
881     FloatRect& m_rect;
882 };
883
884 } // unnamed namespace
885
886 IntRect RenderInline::linesBoundingBox() const
887 {
888     if (!alwaysCreateLineBoxes()) {
889         ASSERT(!firstLineBox());
890         FloatRect floatResult;
891         LinesBoundingBoxGeneratorContext context(floatResult);
892         generateCulledLineBoxRects(context, this);
893         return enclosingIntRect(floatResult);
894     }
895
896     IntRect result;
897     
898     // 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
899     // 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
900     // builds and help us someday figure out why.  We also put in a redundant check of lastLineBox() to avoid the crash for now.
901     ASSERT(!firstLineBox() == !lastLineBox());  // Either both are null or both exist.
902     if (firstLineBox() && lastLineBox()) {
903         // Return the width of the minimal left side and the maximal right side.
904         float logicalLeftSide = 0;
905         float logicalRightSide = 0;
906         for (InlineFlowBox* curr = firstLineBox(); curr; curr = curr->nextLineBox()) {
907             if (curr == firstLineBox() || curr->logicalLeft() < logicalLeftSide)
908                 logicalLeftSide = curr->logicalLeft();
909             if (curr == firstLineBox() || curr->logicalRight() > logicalRightSide)
910                 logicalRightSide = curr->logicalRight();
911         }
912         
913         bool isHorizontal = style().isHorizontalWritingMode();
914         
915         float x = isHorizontal ? logicalLeftSide : firstLineBox()->x();
916         float y = isHorizontal ? firstLineBox()->y() : logicalLeftSide;
917         float width = isHorizontal ? logicalRightSide - logicalLeftSide : lastLineBox()->logicalBottom() - x;
918         float height = isHorizontal ? lastLineBox()->logicalBottom() - y : logicalRightSide - logicalLeftSide;
919         result = enclosingIntRect(FloatRect(x, y, width, height));
920     }
921
922     return result;
923 }
924
925 InlineBox* RenderInline::culledInlineFirstLineBox() const
926 {
927     for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) {
928         if (curr->isFloatingOrOutOfFlowPositioned())
929             continue;
930             
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).
933         if (curr->isBox())
934             return toRenderBox(curr)->inlineBoxWrapper();
935         if (curr->isLineBreak()) {
936             RenderLineBreak* renderBR = toRenderLineBreak(curr);
937             if (renderBR->inlineBoxWrapper())
938                 return renderBR->inlineBoxWrapper();
939         } else if (curr->isRenderInline()) {
940             RenderInline* currInline = toRenderInline(curr);
941             InlineBox* result = currInline->firstLineBoxIncludingCulling();
942             if (result)
943                 return result;
944         } else if (curr->isText()) {
945             RenderText* currText = toRenderText(curr);
946             if (currText->firstTextBox())
947                 return currText->firstTextBox();
948         }
949     }
950     return 0;
951 }
952
953 InlineBox* RenderInline::culledInlineLastLineBox() const
954 {
955     for (RenderObject* curr = lastChild(); curr; curr = curr->previousSibling()) {
956         if (curr->isFloatingOrOutOfFlowPositioned())
957             continue;
958             
959         // We want to get the margin box in the inline direction, and then use our font ascent/descent in the block
960         // direction (aligned to the root box's baseline).
961         if (curr->isBox())
962             return toRenderBox(curr)->inlineBoxWrapper();
963         if (curr->isLineBreak()) {
964             RenderLineBreak* renderBR = toRenderLineBreak(curr);
965             if (renderBR->inlineBoxWrapper())
966                 return renderBR->inlineBoxWrapper();
967         } else if (curr->isRenderInline()) {
968             RenderInline* currInline = toRenderInline(curr);
969             InlineBox* result = currInline->lastLineBoxIncludingCulling();
970             if (result)
971                 return result;
972         } else if (curr->isText()) {
973             RenderText* currText = toRenderText(curr);
974             if (currText->lastTextBox())
975                 return currText->lastTextBox();
976         }
977     }
978     return 0;
979 }
980
981 LayoutRect RenderInline::culledInlineVisualOverflowBoundingBox() const
982 {
983     FloatRect floatResult;
984     LinesBoundingBoxGeneratorContext context(floatResult);
985     generateCulledLineBoxRects(context, this);
986     LayoutRect result(enclosingLayoutRect(floatResult));
987     bool isHorizontal = style().isHorizontalWritingMode();
988     for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) {
989         if (curr->isFloatingOrOutOfFlowPositioned())
990             continue;
991             
992         // For overflow we just have to propagate by hand and recompute it all.
993         if (curr->isBox()) {
994             RenderBox* currBox = toRenderBox(curr);
995             if (!currBox->hasSelfPaintingLayer() && currBox->inlineBoxWrapper()) {
996                 LayoutRect logicalRect = currBox->logicalVisualOverflowRectForPropagation(&style());
997                 if (isHorizontal) {
998                     logicalRect.moveBy(currBox->location());
999                     result.uniteIfNonZero(logicalRect);
1000                 } else {
1001                     logicalRect.moveBy(currBox->location());
1002                     result.uniteIfNonZero(logicalRect.transposedRect());
1003                 }
1004             }
1005         } else if (curr->isRenderInline()) {
1006             // If the child doesn't need line boxes either, then we can recur.
1007             RenderInline* currInline = toRenderInline(curr);
1008             if (!currInline->alwaysCreateLineBoxes())
1009                 result.uniteIfNonZero(currInline->culledInlineVisualOverflowBoundingBox());
1010             else if (!currInline->hasSelfPaintingLayer())
1011                 result.uniteIfNonZero(currInline->linesVisualOverflowBoundingBox());
1012         } else if (curr->isText()) {
1013             // FIXME; Overflow from text boxes is lost. We will need to cache this information in
1014             // InlineTextBoxes.
1015             RenderText* currText = toRenderText(curr);
1016             result.uniteIfNonZero(currText->linesVisualOverflowBoundingBox());
1017         }
1018     }
1019     return result;
1020 }
1021
1022 LayoutRect RenderInline::linesVisualOverflowBoundingBox() const
1023 {
1024     if (!alwaysCreateLineBoxes())
1025         return culledInlineVisualOverflowBoundingBox();
1026
1027     if (!firstLineBox() || !lastLineBox())
1028         return LayoutRect();
1029
1030     // Return the width of the minimal left side and the maximal right side.
1031     LayoutUnit logicalLeftSide = LayoutUnit::max();
1032     LayoutUnit logicalRightSide = LayoutUnit::min();
1033     for (InlineFlowBox* curr = firstLineBox(); curr; curr = curr->nextLineBox()) {
1034         logicalLeftSide = std::min(logicalLeftSide, curr->logicalLeftVisualOverflow());
1035         logicalRightSide = std::max(logicalRightSide, curr->logicalRightVisualOverflow());
1036     }
1037
1038     const RootInlineBox& firstRootBox = firstLineBox()->root();
1039     const RootInlineBox& lastRootBox = lastLineBox()->root();
1040     
1041     LayoutUnit logicalTop = firstLineBox()->logicalTopVisualOverflow(firstRootBox.lineTop());
1042     LayoutUnit logicalWidth = logicalRightSide - logicalLeftSide;
1043     LayoutUnit logicalHeight = lastLineBox()->logicalBottomVisualOverflow(lastRootBox.lineBottom()) - logicalTop;
1044     
1045     LayoutRect rect(logicalLeftSide, logicalTop, logicalWidth, logicalHeight);
1046     if (!style().isHorizontalWritingMode())
1047         rect = rect.transposedRect();
1048     return rect;
1049 }
1050
1051 LayoutRect RenderInline::linesVisualOverflowBoundingBoxInRegion(const RenderRegion* region) const
1052 {
1053     ASSERT(alwaysCreateLineBoxes());
1054     ASSERT(region);
1055
1056     if (!firstLineBox() || !lastLineBox())
1057         return LayoutRect();
1058
1059     // Return the width of the minimal left side and the maximal right side.
1060     LayoutUnit logicalLeftSide = LayoutUnit::max();
1061     LayoutUnit logicalRightSide = LayoutUnit::min();
1062     LayoutUnit logicalTop;
1063     LayoutUnit logicalHeight;
1064     InlineFlowBox* lastInlineInRegion = 0;
1065     for (InlineFlowBox* curr = firstLineBox(); curr; curr = curr->nextLineBox()) {
1066         const RootInlineBox& root = curr->root();
1067         if (root.containingRegion() != region) {
1068             if (lastInlineInRegion)
1069                 break;
1070             continue;
1071         }
1072
1073         if (!lastInlineInRegion)
1074             logicalTop = curr->logicalTopVisualOverflow(root.lineTop());
1075
1076         lastInlineInRegion = curr;
1077
1078         logicalLeftSide = std::min(logicalLeftSide, curr->logicalLeftVisualOverflow());
1079         logicalRightSide = std::max(logicalRightSide, curr->logicalRightVisualOverflow());
1080     }
1081
1082     if (!lastInlineInRegion)
1083         return LayoutRect();
1084
1085     logicalHeight = lastInlineInRegion->logicalBottomVisualOverflow(lastInlineInRegion->root().lineBottom()) - logicalTop;
1086     
1087     LayoutUnit logicalWidth = logicalRightSide - logicalLeftSide;
1088     
1089     LayoutRect rect(logicalLeftSide, logicalTop, logicalWidth, logicalHeight);
1090     if (!style().isHorizontalWritingMode())
1091         rect = rect.transposedRect();
1092     return rect;
1093 }
1094
1095 LayoutRect RenderInline::clippedOverflowRectForRepaint(const RenderLayerModelObject* repaintContainer) const
1096 {
1097     // Only first-letter renderers are allowed in here during layout. They mutate the tree triggering repaints.
1098     ASSERT(!view().layoutStateEnabled() || style().styleType() == FIRST_LETTER);
1099
1100     if (!firstLineBoxIncludingCulling() && !continuation())
1101         return LayoutRect();
1102
1103     LayoutRect repaintRect(linesVisualOverflowBoundingBox());
1104     bool hitRepaintContainer = false;
1105
1106     // We need to add in the in-flow position offsets of any inlines (including us) up to our
1107     // containing block.
1108     RenderBlock* cb = containingBlock();
1109     for (const RenderObject* inlineFlow = this; inlineFlow && inlineFlow->isRenderInline() && inlineFlow != cb;
1110          inlineFlow = inlineFlow->parent()) {
1111          if (inlineFlow == repaintContainer) {
1112             hitRepaintContainer = true;
1113             break;
1114         }
1115         if (inlineFlow->style().hasInFlowPosition() && inlineFlow->hasLayer())
1116             repaintRect.move(toRenderInline(inlineFlow)->layer()->offsetForInFlowPosition());
1117     }
1118
1119     LayoutUnit outlineSize = style().outlineSize();
1120     repaintRect.inflate(outlineSize);
1121
1122     if (hitRepaintContainer || !cb)
1123         return repaintRect;
1124
1125     if (cb->hasOverflowClip())
1126         cb->applyCachedClipAndScrollOffsetForRepaint(repaintRect);
1127
1128     cb->computeRectForRepaint(repaintContainer, repaintRect);
1129
1130     if (outlineSize) {
1131         for (auto& child : childrenOfType<RenderElement>(*this))
1132             repaintRect.unite(child.rectWithOutlineForRepaint(repaintContainer, outlineSize));
1133
1134         if (RenderBoxModelObject* continuation = this->continuation()) {
1135             if (!continuation->isInline() && continuation->parent())
1136                 repaintRect.unite(continuation->rectWithOutlineForRepaint(repaintContainer, outlineSize));
1137         }
1138     }
1139
1140     return repaintRect;
1141 }
1142
1143 LayoutRect RenderInline::rectWithOutlineForRepaint(const RenderLayerModelObject* repaintContainer, LayoutUnit outlineWidth) const
1144 {
1145     LayoutRect r(RenderBoxModelObject::rectWithOutlineForRepaint(repaintContainer, outlineWidth));
1146     for (auto& child : childrenOfType<RenderElement>(*this))
1147         r.unite(child.rectWithOutlineForRepaint(repaintContainer, outlineWidth));
1148     return r;
1149 }
1150
1151 void RenderInline::computeRectForRepaint(const RenderLayerModelObject* repaintContainer, LayoutRect& rect, bool fixed) const
1152 {
1153     // LayoutState is only valid for root-relative repainting
1154     if (view().layoutStateEnabled() && !repaintContainer) {
1155         LayoutState* layoutState = view().layoutState();
1156         if (style().hasInFlowPosition() && layer())
1157             rect.move(layer()->offsetForInFlowPosition());
1158         rect.move(layoutState->m_paintOffset);
1159         if (layoutState->m_clipped)
1160             rect.intersect(layoutState->m_clipRect);
1161         return;
1162     }
1163
1164     if (repaintContainer == this)
1165         return;
1166
1167     bool containerSkipped;
1168     RenderElement* o = container(repaintContainer, &containerSkipped);
1169     if (!o)
1170         return;
1171
1172     LayoutPoint topLeft = rect.location();
1173
1174     if (style().hasInFlowPosition() && layer()) {
1175         // Apply the in-flow position offset when invalidating a rectangle. The layer
1176         // is translated, but the render box isn't, so we need to do this to get the
1177         // right dirty rect. Since this is called from RenderObject::setStyle, the relative or sticky position
1178         // flag on the RenderObject has been cleared, so use the one on the style().
1179         topLeft += layer()->offsetForInFlowPosition();
1180     }
1181     
1182     // FIXME: We ignore the lightweight clipping rect that controls use, since if |o| is in mid-layout,
1183     // its controlClipRect will be wrong. For overflow clip we use the values cached by the layer.
1184     rect.setLocation(topLeft);
1185     if (o->hasOverflowClip()) {
1186         RenderBox* containerBox = toRenderBox(o);
1187         containerBox->applyCachedClipAndScrollOffsetForRepaint(rect);
1188         if (rect.isEmpty())
1189             return;
1190     }
1191
1192     if (containerSkipped) {
1193         // If the repaintContainer is below o, then we need to map the rect into repaintContainer's coordinates.
1194         LayoutSize containerOffset = repaintContainer->offsetFromAncestorContainer(o);
1195         rect.move(-containerOffset);
1196         return;
1197     }
1198     
1199     o->computeRectForRepaint(repaintContainer, rect, fixed);
1200 }
1201
1202 LayoutSize RenderInline::offsetFromContainer(RenderObject* container, const LayoutPoint&, bool* offsetDependsOnPoint) const
1203 {
1204     ASSERT(container == this->container());
1205     
1206     LayoutSize offset;    
1207     if (isInFlowPositioned())
1208         offset += offsetForInFlowPosition();
1209
1210     if (container->isBox())
1211         offset -= toRenderBox(container)->scrolledContentOffset();
1212
1213     if (offsetDependsOnPoint)
1214         *offsetDependsOnPoint = (container->isBox() && container->style().isFlippedBlocksWritingMode()) || container->isRenderFlowThread();
1215
1216     return offset;
1217 }
1218
1219 void RenderInline::mapLocalToContainer(const RenderLayerModelObject* repaintContainer, TransformState& transformState, MapCoordinatesFlags mode, bool* wasFixed) const
1220 {
1221     if (repaintContainer == this)
1222         return;
1223
1224     if (view().layoutStateEnabled() && !repaintContainer) {
1225         LayoutState* layoutState = view().layoutState();
1226         LayoutSize offset = layoutState->m_paintOffset;
1227         if (style().hasInFlowPosition() && layer())
1228             offset += layer()->offsetForInFlowPosition();
1229         transformState.move(offset);
1230         return;
1231     }
1232
1233     bool containerSkipped;
1234     RenderElement* o = container(repaintContainer, &containerSkipped);
1235     if (!o)
1236         return;
1237
1238     if (mode & ApplyContainerFlip && o->isBox()) {
1239         if (o->style().isFlippedBlocksWritingMode()) {
1240             LayoutPoint centerPoint = roundedLayoutPoint(transformState.mappedPoint());
1241             transformState.move(toRenderBox(o)->flipForWritingMode(centerPoint) - centerPoint);
1242         }
1243         mode &= ~ApplyContainerFlip;
1244     }
1245
1246     LayoutSize containerOffset = offsetFromContainer(o, roundedLayoutPoint(transformState.mappedPoint()));
1247
1248     bool preserve3D = mode & UseTransforms && (o->style().preserves3D() || style().preserves3D());
1249     if (mode & UseTransforms && shouldUseTransformFromContainer(o)) {
1250         TransformationMatrix t;
1251         getTransformFromContainer(o, containerOffset, t);
1252         transformState.applyTransform(t, preserve3D ? TransformState::AccumulateTransform : TransformState::FlattenTransform);
1253     } else
1254         transformState.move(containerOffset.width(), containerOffset.height(), preserve3D ? TransformState::AccumulateTransform : TransformState::FlattenTransform);
1255
1256     if (containerSkipped) {
1257         // There can't be a transform between repaintContainer and o, because transforms create containers, so it should be safe
1258         // to just subtract the delta between the repaintContainer and o.
1259         LayoutSize containerOffset = repaintContainer->offsetFromAncestorContainer(o);
1260         transformState.move(-containerOffset.width(), -containerOffset.height(), preserve3D ? TransformState::AccumulateTransform : TransformState::FlattenTransform);
1261         return;
1262     }
1263
1264     o->mapLocalToContainer(repaintContainer, transformState, mode, wasFixed);
1265 }
1266
1267 const RenderObject* RenderInline::pushMappingToContainer(const RenderLayerModelObject* ancestorToStopAt, RenderGeometryMap& geometryMap) const
1268 {
1269     ASSERT(ancestorToStopAt != this);
1270
1271     bool ancestorSkipped;
1272     RenderElement* container = this->container(ancestorToStopAt, &ancestorSkipped);
1273     if (!container)
1274         return 0;
1275
1276     LayoutSize adjustmentForSkippedAncestor;
1277     if (ancestorSkipped) {
1278         // There can't be a transform between repaintContainer and o, because transforms create containers, so it should be safe
1279         // to just subtract the delta between the ancestor and o.
1280         adjustmentForSkippedAncestor = -ancestorToStopAt->offsetFromAncestorContainer(container);
1281     }
1282
1283     bool offsetDependsOnPoint = false;
1284     LayoutSize containerOffset = offsetFromContainer(container, LayoutPoint(), &offsetDependsOnPoint);
1285
1286     bool preserve3D = container->style().preserves3D() || style().preserves3D();
1287     if (shouldUseTransformFromContainer(container)) {
1288         TransformationMatrix t;
1289         getTransformFromContainer(container, containerOffset, t);
1290         t.translateRight(adjustmentForSkippedAncestor.width(), adjustmentForSkippedAncestor.height()); // FIXME: right?
1291         geometryMap.push(this, t, preserve3D, offsetDependsOnPoint);
1292     } else {
1293         containerOffset += adjustmentForSkippedAncestor;
1294         geometryMap.push(this, containerOffset, preserve3D, offsetDependsOnPoint);
1295     }
1296     
1297     return ancestorSkipped ? ancestorToStopAt : container;
1298 }
1299
1300 void RenderInline::updateDragState(bool dragOn)
1301 {
1302     RenderBoxModelObject::updateDragState(dragOn);
1303     if (RenderBoxModelObject* continuation = this->continuation())
1304         continuation->updateDragState(dragOn);
1305 }
1306
1307 void RenderInline::childBecameNonInline(RenderObject* child)
1308 {
1309     // We have to split the parent flow.
1310     RenderBlock* newBox = containingBlock()->createAnonymousBlock();
1311     RenderBoxModelObject* oldContinuation = continuation();
1312     setContinuation(newBox);
1313     RenderObject* beforeChild = child->nextSibling();
1314     removeChildInternal(*child, NotifyChildren);
1315     splitFlow(beforeChild, newBox, child, oldContinuation);
1316 }
1317
1318 void RenderInline::updateHitTestResult(HitTestResult& result, const LayoutPoint& point)
1319 {
1320     if (result.innerNode())
1321         return;
1322
1323     LayoutPoint localPoint(point);
1324     if (Element* element = this->element()) {
1325         if (isInlineElementContinuation()) {
1326             // We're in the continuation of a split inline.  Adjust our local point to be in the coordinate space
1327             // of the principal renderer's containing block.  This will end up being the innerNonSharedNode.
1328             RenderBlock* firstBlock = element->renderer()->containingBlock();
1329             
1330             // Get our containing block.
1331             RenderBox* block = containingBlock();
1332             localPoint.moveBy(block->location() - firstBlock->locationOffset());
1333         }
1334
1335         result.setInnerNode(element);
1336         if (!result.innerNonSharedNode())
1337             result.setInnerNonSharedNode(element);
1338         result.setLocalPoint(localPoint);
1339     }
1340 }
1341
1342 void RenderInline::dirtyLineBoxes(bool fullLayout)
1343 {
1344     if (fullLayout) {
1345         m_lineBoxes.deleteLineBoxes();
1346         return;
1347     }
1348
1349     if (!alwaysCreateLineBoxes()) {
1350         // We have to grovel into our children in order to dirty the appropriate lines.
1351         for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) {
1352             if (curr->isFloatingOrOutOfFlowPositioned())
1353                 continue;
1354             if (curr->isBox() && !curr->needsLayout()) {
1355                 RenderBox* currBox = toRenderBox(curr);
1356                 if (currBox->inlineBoxWrapper())
1357                     currBox->inlineBoxWrapper()->root().markDirty();
1358             } else if (!curr->selfNeedsLayout()) {
1359                 if (curr->isRenderInline()) {
1360                     RenderInline* currInline = toRenderInline(curr);
1361                     for (InlineFlowBox* childLine = currInline->firstLineBox(); childLine; childLine = childLine->nextLineBox())
1362                         childLine->root().markDirty();
1363                 } else if (curr->isText()) {
1364                     RenderText* currText = toRenderText(curr);
1365                     for (InlineTextBox* childText = currText->firstTextBox(); childText; childText = childText->nextTextBox())
1366                         childText->root().markDirty();
1367                 } else if (curr->isLineBreak()) {
1368                     RenderLineBreak* currBR = toRenderLineBreak(curr);
1369                     if (currBR->inlineBoxWrapper())
1370                         currBR->inlineBoxWrapper()->root().markDirty();
1371                 }
1372             }
1373         }
1374     } else
1375         m_lineBoxes.dirtyLineBoxes();
1376 }
1377
1378 void RenderInline::deleteLines()
1379 {
1380     m_lineBoxes.deleteLineBoxTree();
1381 }
1382
1383 std::unique_ptr<InlineFlowBox> RenderInline::createInlineFlowBox()
1384 {
1385     return std::make_unique<InlineFlowBox>(*this);
1386 }
1387
1388 InlineFlowBox* RenderInline::createAndAppendInlineFlowBox()
1389 {
1390     setAlwaysCreateLineBoxes();
1391     auto newFlowBox = createInlineFlowBox();
1392     auto flowBox = newFlowBox.get();
1393     m_lineBoxes.appendLineBox(std::move(newFlowBox));
1394     return flowBox;
1395 }
1396
1397 LayoutUnit RenderInline::lineHeight(bool firstLine, LineDirectionMode /*direction*/, LinePositionMode /*linePositionMode*/) const
1398 {
1399     if (firstLine && document().styleSheetCollection().usesFirstLineRules()) {
1400         const RenderStyle& firstLineStyle = this->firstLineStyle();
1401         if (&firstLineStyle != &style())
1402             return firstLineStyle.computedLineHeight(&view());
1403     }
1404
1405     return style().computedLineHeight(&view());
1406 }
1407
1408 int RenderInline::baselinePosition(FontBaseline baselineType, bool firstLine, LineDirectionMode direction, LinePositionMode linePositionMode) const
1409 {
1410     const RenderStyle& style = firstLine ? firstLineStyle() : this->style();
1411     const FontMetrics& fontMetrics = style.fontMetrics();
1412     return fontMetrics.ascent(baselineType) + (lineHeight(firstLine, direction, linePositionMode) - fontMetrics.height()) / 2;
1413 }
1414
1415 LayoutSize RenderInline::offsetForInFlowPositionedInline(const RenderBox* child) const
1416 {
1417     // FIXME: This function isn't right with mixed writing modes.
1418
1419     ASSERT(isInFlowPositioned());
1420     if (!isInFlowPositioned())
1421         return LayoutSize();
1422
1423     // When we have an enclosing relpositioned inline, we need to add in the offset of the first line
1424     // box from the rest of the content, but only in the cases where we know we're positioned
1425     // relative to the inline itself.
1426
1427     LayoutSize logicalOffset;
1428     LayoutUnit inlinePosition;
1429     LayoutUnit blockPosition;
1430     if (firstLineBox()) {
1431         inlinePosition = roundedLayoutUnit(firstLineBox()->logicalLeft());
1432         blockPosition = firstLineBox()->logicalTop();
1433     } else {
1434         inlinePosition = layer()->staticInlinePosition();
1435         blockPosition = layer()->staticBlockPosition();
1436     }
1437
1438     if (!child->style().hasStaticInlinePosition(style().isHorizontalWritingMode()))
1439         logicalOffset.setWidth(inlinePosition);
1440
1441     // This is not terribly intuitive, but we have to match other browsers.  Despite being a block display type inside
1442     // an inline, we still keep our x locked to the left of the relative positioned inline.  Arguably the correct
1443     // behavior would be to go flush left to the block that contains the inline, but that isn't what other browsers
1444     // do.
1445     else if (!child->style().isOriginalDisplayInlineType())
1446         // Avoid adding in the left border/padding of the containing block twice.  Subtract it out.
1447         logicalOffset.setWidth(inlinePosition - child->containingBlock()->borderAndPaddingLogicalLeft());
1448
1449     if (!child->style().hasStaticBlockPosition(style().isHorizontalWritingMode()))
1450         logicalOffset.setHeight(blockPosition);
1451
1452     return style().isHorizontalWritingMode() ? logicalOffset : logicalOffset.transposedSize();
1453 }
1454
1455 void RenderInline::imageChanged(WrappedImagePtr, const IntRect*)
1456 {
1457     if (!parent())
1458         return;
1459         
1460     // FIXME: We can do better.
1461     repaint();
1462 }
1463
1464 void RenderInline::addFocusRingRects(Vector<IntRect>& rects, const LayoutPoint& additionalOffset, const RenderLayerModelObject* paintContainer)
1465 {
1466     AbsoluteRectsGeneratorContext context(rects, additionalOffset);
1467     generateLineBoxRects(context);
1468
1469     for (auto& child : childrenOfType<RenderElement>(*this)) {
1470         if (child.isListMarker())
1471             continue;
1472         FloatPoint pos(additionalOffset);
1473         // FIXME: This doesn't work correctly with transforms.
1474         if (child.hasLayer())
1475             pos = child.localToContainerPoint(FloatPoint(), paintContainer);
1476         else if (child.isBox())
1477             pos.move(toRenderBox(child).locationOffset());
1478         child.addFocusRingRects(rects, flooredIntPoint(pos), paintContainer);
1479     }
1480
1481     if (RenderBoxModelObject* continuation = this->continuation()) {
1482         if (continuation->isInline())
1483             continuation->addFocusRingRects(rects, flooredLayoutPoint(LayoutPoint(additionalOffset + continuation->containingBlock()->location() - containingBlock()->location())), paintContainer);
1484         else
1485             continuation->addFocusRingRects(rects, flooredLayoutPoint(LayoutPoint(additionalOffset + toRenderBox(continuation)->location() - containingBlock()->location())), paintContainer);
1486     }
1487 }
1488
1489 void RenderInline::paintOutline(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
1490 {
1491     if (!hasOutline())
1492         return;
1493     
1494     RenderStyle& styleToUse = style();
1495     // Only paint the focus ring by hand if the theme isn't able to draw it.
1496     if (styleToUse.outlineStyleIsAuto() && !theme().supportsFocusRing(&styleToUse))
1497         paintFocusRing(paintInfo, paintOffset, &styleToUse);
1498     else if (hasOutlineAnnotation() && !theme().supportsFocusRing(&styleToUse))
1499         addPDFURLRect(paintInfo, paintOffset);
1500
1501     GraphicsContext* graphicsContext = paintInfo.context;
1502     if (graphicsContext->paintingDisabled())
1503         return;
1504
1505     if (styleToUse.outlineStyleIsAuto() || styleToUse.outlineStyle() == BNONE)
1506         return;
1507
1508     Vector<LayoutRect> rects;
1509
1510     rects.append(LayoutRect());
1511     for (InlineFlowBox* curr = firstLineBox(); curr; curr = curr->nextLineBox()) {
1512         const RootInlineBox& rootBox = curr->root();
1513         LayoutUnit top = std::max<LayoutUnit>(rootBox.lineTop(), curr->logicalTop());
1514         LayoutUnit bottom = std::min<LayoutUnit>(rootBox.lineBottom(), curr->logicalBottom());
1515         rects.append(LayoutRect(curr->x(), top, curr->logicalWidth(), bottom - top));
1516     }
1517     rects.append(LayoutRect());
1518
1519     Color outlineColor = styleToUse.visitedDependentColor(CSSPropertyOutlineColor);
1520     bool useTransparencyLayer = outlineColor.hasAlpha();
1521     if (useTransparencyLayer) {
1522         graphicsContext->beginTransparencyLayer(static_cast<float>(outlineColor.alpha()) / 255);
1523         outlineColor = Color(outlineColor.red(), outlineColor.green(), outlineColor.blue());
1524     }
1525
1526     for (unsigned i = 1; i < rects.size() - 1; i++)
1527         paintOutlineForLine(graphicsContext, paintOffset, rects.at(i - 1), rects.at(i), rects.at(i + 1), outlineColor);
1528
1529     if (useTransparencyLayer)
1530         graphicsContext->endTransparencyLayer();
1531 }
1532
1533 void RenderInline::paintOutlineForLine(GraphicsContext* graphicsContext, const LayoutPoint& paintOffset,
1534                                        const LayoutRect& lastline, const LayoutRect& thisline, const LayoutRect& nextline,
1535                                        const Color outlineColor)
1536 {
1537     const RenderStyle& styleToUse = style();
1538     int outlineWidth = styleToUse.outlineWidth();
1539     EBorderStyle outlineStyle = styleToUse.outlineStyle();
1540
1541     bool antialias = shouldAntialiasLines(graphicsContext);
1542
1543     int offset = style().outlineOffset();
1544
1545     LayoutRect box(LayoutPoint(paintOffset.x() + thisline.x() - offset, paintOffset.y() + thisline.y() - offset),
1546         LayoutSize(thisline.width() + offset, thisline.height() + offset));
1547
1548     IntRect pixelSnappedBox = pixelSnappedIntRect(box);
1549     if (pixelSnappedBox.isEmpty())
1550         return;
1551     IntRect pixelSnappedLastLine = pixelSnappedIntRect(paintOffset.x() + lastline.x(), 0, lastline.width(), 0);
1552     IntRect pixelSnappedNextLine = pixelSnappedIntRect(paintOffset.x() + nextline.x(), 0, nextline.width(), 0);
1553     
1554     // left edge
1555     drawLineForBoxSide(graphicsContext,
1556         pixelSnappedBox.x() - outlineWidth,
1557         pixelSnappedBox.y() - (lastline.isEmpty() || thisline.x() < lastline.x() || (lastline.maxX() - 1) <= thisline.x() ? outlineWidth : 0),
1558         pixelSnappedBox.x(),
1559         pixelSnappedBox.maxY() + (nextline.isEmpty() || thisline.x() <= nextline.x() || (nextline.maxX() - 1) <= thisline.x() ? outlineWidth : 0),
1560         BSLeft,
1561         outlineColor, outlineStyle,
1562         (lastline.isEmpty() || thisline.x() < lastline.x() || (lastline.maxX() - 1) <= thisline.x() ? outlineWidth : -outlineWidth),
1563         (nextline.isEmpty() || thisline.x() <= nextline.x() || (nextline.maxX() - 1) <= thisline.x() ? outlineWidth : -outlineWidth),
1564         antialias);
1565     
1566     // right edge
1567     drawLineForBoxSide(graphicsContext,
1568         pixelSnappedBox.maxX(),
1569         pixelSnappedBox.y() - (lastline.isEmpty() || lastline.maxX() < thisline.maxX() || (thisline.maxX() - 1) <= lastline.x() ? outlineWidth : 0),
1570         pixelSnappedBox.maxX() + outlineWidth,
1571         pixelSnappedBox.maxY() + (nextline.isEmpty() || nextline.maxX() <= thisline.maxX() || (thisline.maxX() - 1) <= nextline.x() ? outlineWidth : 0),
1572         BSRight,
1573         outlineColor, outlineStyle,
1574         (lastline.isEmpty() || lastline.maxX() < thisline.maxX() || (thisline.maxX() - 1) <= lastline.x() ? outlineWidth : -outlineWidth),
1575         (nextline.isEmpty() || nextline.maxX() <= thisline.maxX() || (thisline.maxX() - 1) <= nextline.x() ? outlineWidth : -outlineWidth),
1576         antialias);
1577     // upper edge
1578     if (thisline.x() < lastline.x())
1579         drawLineForBoxSide(graphicsContext,
1580             pixelSnappedBox.x() - outlineWidth,
1581             pixelSnappedBox.y() - outlineWidth,
1582             std::min(pixelSnappedBox.maxX() + outlineWidth, (lastline.isEmpty() ? 1000000 : pixelSnappedLastLine.x())),
1583             pixelSnappedBox.y(),
1584             BSTop, outlineColor, outlineStyle,
1585             outlineWidth,
1586             (!lastline.isEmpty() && paintOffset.x() + lastline.x() + 1 < pixelSnappedBox.maxX() + outlineWidth) ? -outlineWidth : outlineWidth,
1587             antialias);
1588     
1589     if (lastline.maxX() < thisline.maxX())
1590         drawLineForBoxSide(graphicsContext,
1591             std::max(lastline.isEmpty() ? -1000000 : pixelSnappedLastLine.maxX(), pixelSnappedBox.x() - outlineWidth),
1592             pixelSnappedBox.y() - outlineWidth,
1593             pixelSnappedBox.maxX() + outlineWidth,
1594             pixelSnappedBox.y(),
1595             BSTop, outlineColor, outlineStyle,
1596             (!lastline.isEmpty() && pixelSnappedBox.x() - outlineWidth < paintOffset.x() + lastline.maxX()) ? -outlineWidth : outlineWidth,
1597             outlineWidth, antialias);
1598
1599     if (thisline.x() == thisline.maxX())
1600           drawLineForBoxSide(graphicsContext,
1601             pixelSnappedBox.x() - outlineWidth,
1602             pixelSnappedBox.y() - outlineWidth,
1603             pixelSnappedBox.maxX() + outlineWidth,
1604             pixelSnappedBox.y(),
1605             BSTop, outlineColor, outlineStyle,
1606             outlineWidth,
1607             outlineWidth,
1608             antialias);
1609
1610     // lower edge
1611     if (thisline.x() < nextline.x())
1612         drawLineForBoxSide(graphicsContext,
1613             pixelSnappedBox.x() - outlineWidth,
1614             pixelSnappedBox.maxY(),
1615             std::min(pixelSnappedBox.maxX() + outlineWidth, !nextline.isEmpty() ? pixelSnappedNextLine.x() + 1 : 1000000),
1616             pixelSnappedBox.maxY() + outlineWidth,
1617             BSBottom, outlineColor, outlineStyle,
1618             outlineWidth,
1619             (!nextline.isEmpty() && paintOffset.x() + nextline.x() + 1 < pixelSnappedBox.maxX() + outlineWidth) ? -outlineWidth : outlineWidth,
1620             antialias);
1621     
1622     if (nextline.maxX() < thisline.maxX())
1623         drawLineForBoxSide(graphicsContext,
1624             std::max(!nextline.isEmpty() ? pixelSnappedNextLine.maxX() : -1000000, pixelSnappedBox.x() - outlineWidth),
1625             pixelSnappedBox.maxY(),
1626             pixelSnappedBox.maxX() + outlineWidth,
1627             pixelSnappedBox.maxY() + outlineWidth,
1628             BSBottom, outlineColor, outlineStyle,
1629             (!nextline.isEmpty() && pixelSnappedBox.x() - outlineWidth < paintOffset.x() + nextline.maxX()) ? -outlineWidth : outlineWidth,
1630             outlineWidth, antialias);
1631
1632     if (thisline.x() == thisline.maxX())
1633           drawLineForBoxSide(graphicsContext,
1634             pixelSnappedBox.x() - outlineWidth,
1635             pixelSnappedBox.maxY(),
1636             pixelSnappedBox.maxX() + outlineWidth,
1637             pixelSnappedBox.maxY() + outlineWidth,
1638             BSBottom, outlineColor, outlineStyle,
1639             outlineWidth,
1640             outlineWidth,
1641             antialias);
1642 }
1643
1644 #if ENABLE(DASHBOARD_SUPPORT)
1645 void RenderInline::addAnnotatedRegions(Vector<AnnotatedRegionValue>& regions)
1646 {
1647     // Convert the style regions to absolute coordinates.
1648     if (style().visibility() != VISIBLE)
1649         return;
1650
1651     const Vector<StyleDashboardRegion>& styleRegions = style().dashboardRegions();
1652     unsigned i, count = styleRegions.size();
1653     for (i = 0; i < count; i++) {
1654         StyleDashboardRegion styleRegion = styleRegions[i];
1655
1656         LayoutRect linesBoundingBox = this->linesBoundingBox();
1657         LayoutUnit w = linesBoundingBox.width();
1658         LayoutUnit h = linesBoundingBox.height();
1659
1660         AnnotatedRegionValue region;
1661         region.label = styleRegion.label;
1662         region.bounds = LayoutRect(linesBoundingBox.x() + styleRegion.offset.left().value(),
1663                                 linesBoundingBox.y() + styleRegion.offset.top().value(),
1664                                 w - styleRegion.offset.left().value() - styleRegion.offset.right().value(),
1665                                 h - styleRegion.offset.top().value() - styleRegion.offset.bottom().value());
1666         region.type = styleRegion.type;
1667
1668         RenderObject* container = containingBlock();
1669         if (!container)
1670             container = this;
1671
1672         region.clip = region.bounds;
1673         container->computeAbsoluteRepaintRect(region.clip);
1674         if (region.clip.height() < 0) {
1675             region.clip.setHeight(0);
1676             region.clip.setWidth(0);
1677         }
1678
1679         FloatPoint absPos = container->localToAbsolute();
1680         region.bounds.setX(absPos.x() + region.bounds.x());
1681         region.bounds.setY(absPos.y() + region.bounds.y());
1682
1683         regions.append(region);
1684     }
1685 }
1686 #endif
1687
1688 } // namespace WebCore