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