• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "core/rendering/RenderInline.h"
25 
26 #include "core/dom/FullscreenElementStack.h"
27 #include "core/page/Chrome.h"
28 #include "core/page/Page.h"
29 #include "core/rendering/GraphicsContextAnnotator.h"
30 #include "core/rendering/HitTestResult.h"
31 #include "core/rendering/InlineTextBox.h"
32 #include "core/rendering/LayoutRectRecorder.h"
33 #include "core/rendering/RenderBlock.h"
34 #include "core/rendering/RenderFlowThread.h"
35 #include "core/rendering/RenderFullScreen.h"
36 #include "core/rendering/RenderGeometryMap.h"
37 #include "core/rendering/RenderLayer.h"
38 #include "core/rendering/RenderTheme.h"
39 #include "core/rendering/RenderView.h"
40 #include "core/rendering/style/StyleInheritedData.h"
41 #include "platform/geometry/FloatQuad.h"
42 #include "platform/geometry/TransformState.h"
43 #include "platform/graphics/GraphicsContext.h"
44 
45 using namespace std;
46 
47 namespace WebCore {
48 
RenderInline(Element * element)49 RenderInline::RenderInline(Element* element)
50     : RenderBoxModelObject(element)
51     , m_alwaysCreateLineBoxes(false)
52 {
53     setChildrenInline(true);
54 }
55 
createAnonymous(Document * document)56 RenderInline* RenderInline::createAnonymous(Document* document)
57 {
58     RenderInline* renderer = new RenderInline(0);
59     renderer->setDocumentForAnonymous(document);
60     return renderer;
61 }
62 
willBeDestroyed()63 void RenderInline::willBeDestroyed()
64 {
65 #if !ASSERT_DISABLED
66     // Make sure we do not retain "this" in the continuation outline table map of our containing blocks.
67     if (parent() && style()->visibility() == VISIBLE && hasOutline()) {
68         bool containingBlockPaintsContinuationOutline = continuation() || isInlineElementContinuation();
69         if (containingBlockPaintsContinuationOutline) {
70             if (RenderBlock* cb = containingBlock()) {
71                 if (RenderBlock* cbCb = cb->containingBlock())
72                     ASSERT(!cbCb->paintsContinuationOutline(this));
73             }
74         }
75     }
76 #endif
77 
78     // Make sure to destroy anonymous children first while they are still connected to the rest of the tree, so that they will
79     // properly dirty line boxes that they are removed from.  Effects that do :before/:after only on hover could crash otherwise.
80     children()->destroyLeftoverChildren();
81 
82     // Destroy our continuation before anything other than anonymous children.
83     // The reason we don't destroy it before anonymous children is that they may
84     // have continuations of their own that are anonymous children of our continuation.
85     RenderBoxModelObject* continuation = this->continuation();
86     if (continuation) {
87         continuation->destroy();
88         setContinuation(0);
89     }
90 
91     if (!documentBeingDestroyed()) {
92         if (firstLineBox()) {
93             // We can't wait for RenderBoxModelObject::destroy to clear the selection,
94             // because by then we will have nuked the line boxes.
95             // FIXME: The FrameSelection should be responsible for this when it
96             // is notified of DOM mutations.
97             if (isSelectionBorder())
98                 view()->clearSelection();
99 
100             // If line boxes are contained inside a root, that means we're an inline.
101             // In that case, we need to remove all the line boxes so that the parent
102             // lines aren't pointing to deleted children. If the first line box does
103             // not have a parent that means they are either already disconnected or
104             // root lines that can just be destroyed without disconnecting.
105             if (firstLineBox()->parent()) {
106                 for (InlineFlowBox* box = firstLineBox(); box; box = box->nextLineBox())
107                     box->remove();
108             }
109         } else if (parent())
110             parent()->dirtyLinesFromChangedChild(this);
111     }
112 
113     m_lineBoxes.deleteLineBoxes();
114 
115     RenderBoxModelObject::willBeDestroyed();
116 }
117 
inlineElementContinuation() const118 RenderInline* RenderInline::inlineElementContinuation() const
119 {
120     RenderBoxModelObject* continuation = this->continuation();
121     if (!continuation || continuation->isInline())
122         return toRenderInline(continuation);
123     return toRenderBlock(continuation)->inlineElementContinuation();
124 }
125 
updateFromStyle()126 void RenderInline::updateFromStyle()
127 {
128     RenderBoxModelObject::updateFromStyle();
129 
130     // FIXME: Is this still needed. Was needed for run-ins, since run-in is considered a block display type.
131     setInline(true);
132 
133     // FIXME: Support transforms and reflections on inline flows someday.
134     setHasTransform(false);
135     setHasReflection(false);
136 }
137 
inFlowPositionedInlineAncestor(RenderObject * p)138 static RenderObject* inFlowPositionedInlineAncestor(RenderObject* p)
139 {
140     while (p && p->isRenderInline()) {
141         if (p->isInFlowPositioned())
142             return p;
143         p = p->parent();
144     }
145     return 0;
146 }
147 
updateStyleOfAnonymousBlockContinuations(RenderObject * block,const RenderStyle * newStyle,const RenderStyle * oldStyle)148 static void updateStyleOfAnonymousBlockContinuations(RenderObject* block, const RenderStyle* newStyle, const RenderStyle* oldStyle)
149 {
150     for (;block && block->isAnonymousBlock(); block = block->nextSibling()) {
151         if (!toRenderBlock(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 = toRenderBlock(block)->inlineElementContinuation();
156         if (oldStyle->hasInFlowPosition() && inFlowPositionedInlineAncestor(cont))
157             continue;
158         RefPtr<RenderStyle> blockStyle = RenderStyle::createAnonymousStyleWithDisplay(block->style(), BLOCK);
159         blockStyle->setPosition(newStyle->position());
160         block->setStyle(blockStyle);
161     }
162 }
163 
styleDidChange(StyleDifference diff,const RenderStyle * oldStyle)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(block, newStyle, oldStyle);
191     }
192 
193     if (!m_alwaysCreateLineBoxes) {
194         bool alwaysCreateLineBoxes = hasSelfPaintingLayer() || hasBoxDecorations() || newStyle->hasPadding() || newStyle->hasMargin() || hasOutline();
195         if (oldStyle && alwaysCreateLineBoxes) {
196             dirtyLineBoxes(false);
197             setNeedsLayout();
198         }
199         m_alwaysCreateLineBoxes = alwaysCreateLineBoxes;
200     }
201 }
202 
updateAlwaysCreateLineBoxes(bool fullLayout)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 (m_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->hasRegionsWithStyling());
221 
222     if (!alwaysCreateLineBoxes && checkFonts && document().styleEngine()->usesFirstLineRules()) {
223         // Have to check the first line style as well.
224         parentStyle = parent()->style(true);
225         RenderStyle* childStyle = style(true);
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         m_alwaysCreateLineBoxes = true;
235     }
236 }
237 
localCaretRect(InlineBox * inlineBox,int,LayoutUnit * extraWidthToEndOfLine)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 
addChild(RenderObject * newChild,RenderObject * beforeChild)262 void RenderInline::addChild(RenderObject* newChild, RenderObject* beforeChild)
263 {
264     if (continuation())
265         return addChildToContinuation(newChild, beforeChild);
266     return addChildIgnoringContinuation(newChild, beforeChild);
267 }
268 
nextContinuation(RenderObject * renderer)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 
continuationBefore(RenderObject * beforeChild)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 
addChildIgnoringContinuation(RenderObject * newChild,RenderObject * beforeChild)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         RefPtr<RenderStyle> 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 (RenderObject* positionedAncestor = inFlowPositionedInlineAncestor(this))
317             newStyle->setPosition(positionedAncestor->style()->position());
318 
319         RenderBlockFlow* newBox = RenderBlockFlow::createAnonymous(&document());
320         newBox->setStyle(newStyle.release());
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 
clone() const333 RenderInline* RenderInline::clone() const
334 {
335     RenderInline* cloneInline = new RenderInline(node());
336     cloneInline->setStyle(style());
337     cloneInline->setFlowThreadState(flowThreadState());
338     return cloneInline;
339 }
340 
splitInlines(RenderBlock * fromBlock,RenderBlock * toBlock,RenderBlock * middleBlock,RenderObject * beforeChild,RenderBoxModelObject * oldCont)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     RenderInline* cloneInline = clone();
347     cloneInline->setContinuation(oldCont);
348 
349     // If we're splitting the inline containing the fullscreened element,
350     // |beforeChild| may be the renderer for the fullscreened element. However,
351     // that renderer is wrapped in a RenderFullScreen, so |this| is not its
352     // parent. Since the splitting logic expects |this| to be the parent, set
353     // |beforeChild| to be the RenderFullScreen.
354     if (FullscreenElementStack* fullscreen = FullscreenElementStack::fromIfExists(&document())) {
355         const Element* fullScreenElement = fullscreen->webkitCurrentFullScreenElement();
356         if (fullScreenElement && beforeChild && beforeChild->node() == fullScreenElement)
357             beforeChild = fullscreen->fullScreenRenderer();
358     }
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         cloneInline->addChildIgnoringContinuation(children()->removeChildNode(this, tmp), 0);
367         tmp->setNeedsLayoutAndPrefWidthsRecalc();
368     }
369 
370     // Hook |clone| up as the continuation of the middle block.
371     middleBlock->setContinuation(cloneInline);
372 
373     // We have been reparented and are now under the fromBlock.  We need
374     // to walk up our inline parent chain until we hit the containing block.
375     // Once we hit the containing block we're done.
376     RenderBoxModelObject* curr = toRenderBoxModelObject(parent());
377     RenderBoxModelObject* currChild = this;
378 
379     // FIXME: Because splitting is O(n^2) as tags nest pathologically, we cap the depth at which we're willing to clone.
380     // There will eventually be a better approach to this problem that will let us nest to a much
381     // greater depth (see bugzilla bug 13430) but for now we have a limit.  This *will* result in
382     // incorrect rendering, but the alternative is to hang forever.
383     unsigned splitDepth = 1;
384     const unsigned cMaxSplitDepth = 200;
385     while (curr && curr != fromBlock) {
386         ASSERT(curr->isRenderInline());
387         if (splitDepth < cMaxSplitDepth) {
388             // Create a new clone.
389             RenderInline* cloneChild = cloneInline;
390             cloneInline = toRenderInline(curr)->clone();
391 
392             // Insert our child clone as the first child.
393             cloneInline->addChildIgnoringContinuation(cloneChild, 0);
394 
395             // Hook the clone up as a continuation of |curr|.
396             RenderInline* inlineCurr = toRenderInline(curr);
397             oldCont = inlineCurr->continuation();
398             inlineCurr->setContinuation(cloneInline);
399             cloneInline->setContinuation(oldCont);
400 
401             // Now we need to take all of the children starting from the first child
402             // *after* currChild and append them all to the clone.
403             o = currChild->nextSibling();
404             while (o) {
405                 RenderObject* tmp = o;
406                 o = tmp->nextSibling();
407                 cloneInline->addChildIgnoringContinuation(inlineCurr->children()->removeChildNode(curr, tmp), 0);
408                 tmp->setNeedsLayoutAndPrefWidthsRecalc();
409             }
410         }
411 
412         // Keep walking up the chain.
413         currChild = curr;
414         curr = toRenderBoxModelObject(curr->parent());
415         splitDepth++;
416     }
417 
418     // Now we are at the block level. We need to put the clone into the toBlock.
419     toBlock->children()->appendChildNode(toBlock, cloneInline);
420 
421     // Now take all the children after currChild and remove them from the fromBlock
422     // and put them in the toBlock.
423     o = currChild->nextSibling();
424     while (o) {
425         RenderObject* tmp = o;
426         o = tmp->nextSibling();
427         toBlock->children()->appendChildNode(toBlock, fromBlock->children()->removeChildNode(fromBlock, tmp));
428     }
429 }
430 
splitFlow(RenderObject * beforeChild,RenderBlock * newBlockBox,RenderObject * newChild,RenderBoxModelObject * oldCont)431 void RenderInline::splitFlow(RenderObject* beforeChild, RenderBlock* newBlockBox,
432                              RenderObject* newChild, RenderBoxModelObject* oldCont)
433 {
434     RenderBlock* pre = 0;
435     RenderBlock* block = containingBlock();
436 
437     // Delete our line boxes before we do the inline split into continuations.
438     block->deleteLineBoxTree();
439 
440     bool madeNewBeforeBlock = false;
441     if (block->isAnonymousBlock() && (!block->parent() || !block->parent()->createsAnonymousWrapper())) {
442         // We can reuse this block and make it the preBlock of the next continuation.
443         pre = block;
444         pre->removePositionedObjects(0);
445         if (pre->isRenderBlockFlow())
446             toRenderBlockFlow(pre)->removeFloatingObjects();
447         block = block->containingBlock();
448     } else {
449         // No anonymous block available for use.  Make one.
450         pre = block->createAnonymousBlock();
451         madeNewBeforeBlock = true;
452     }
453 
454     RenderBlock* post = toRenderBlock(pre->createAnonymousBoxWithSameTypeAs(block));
455 
456     RenderObject* boxFirst = madeNewBeforeBlock ? block->firstChild() : pre->nextSibling();
457     if (madeNewBeforeBlock)
458         block->children()->insertChildNode(block, pre, boxFirst);
459     block->children()->insertChildNode(block, newBlockBox, boxFirst);
460     block->children()->insertChildNode(block, post, boxFirst);
461     block->setChildrenInline(false);
462 
463     if (madeNewBeforeBlock) {
464         RenderObject* o = boxFirst;
465         while (o) {
466             RenderObject* no = o;
467             o = no->nextSibling();
468             pre->children()->appendChildNode(pre, block->children()->removeChildNode(block, no));
469             no->setNeedsLayoutAndPrefWidthsRecalc();
470         }
471     }
472 
473     splitInlines(pre, post, newBlockBox, beforeChild, oldCont);
474 
475     // We already know the newBlockBox isn't going to contain inline kids, so avoid wasting
476     // time in makeChildrenNonInline by just setting this explicitly up front.
477     newBlockBox->setChildrenInline(false);
478 
479     newBlockBox->addChild(newChild);
480 
481     // Always just do a full layout in order to ensure that line boxes (especially wrappers for images)
482     // get deleted properly.  Because objects moves from the pre block into the post block, we want to
483     // make new line boxes instead of leaving the old line boxes around.
484     pre->setNeedsLayoutAndPrefWidthsRecalc();
485     block->setNeedsLayoutAndPrefWidthsRecalc();
486     post->setNeedsLayoutAndPrefWidthsRecalc();
487 }
488 
addChildToContinuation(RenderObject * newChild,RenderObject * beforeChild)489 void RenderInline::addChildToContinuation(RenderObject* newChild, RenderObject* beforeChild)
490 {
491     RenderBoxModelObject* flow = continuationBefore(beforeChild);
492     ASSERT(!beforeChild || beforeChild->parent()->isRenderBlock() || beforeChild->parent()->isRenderInline());
493     RenderBoxModelObject* beforeChildParent = 0;
494     if (beforeChild)
495         beforeChildParent = toRenderBoxModelObject(beforeChild->parent());
496     else {
497         RenderBoxModelObject* cont = nextContinuation(flow);
498         if (cont)
499             beforeChildParent = cont;
500         else
501             beforeChildParent = flow;
502     }
503 
504     if (newChild->isFloatingOrOutOfFlowPositioned())
505         return beforeChildParent->addChildIgnoringContinuation(newChild, beforeChild);
506 
507     // A continuation always consists of two potential candidates: an inline or an anonymous
508     // block box holding block children.
509     bool childInline = newChild->isInline();
510     bool bcpInline = beforeChildParent->isInline();
511     bool flowInline = flow->isInline();
512 
513     if (flow == beforeChildParent)
514         return flow->addChildIgnoringContinuation(newChild, beforeChild);
515     else {
516         // The goal here is to match up if we can, so that we can coalesce and create the
517         // minimal # of continuations needed for the inline.
518         if (childInline == bcpInline || (beforeChild && beforeChild->isInline()))
519             return beforeChildParent->addChildIgnoringContinuation(newChild, beforeChild);
520         if (flowInline == childInline)
521             return flow->addChildIgnoringContinuation(newChild, 0); // Just treat like an append.
522         return beforeChildParent->addChildIgnoringContinuation(newChild, beforeChild);
523     }
524 }
525 
paint(PaintInfo & paintInfo,const LayoutPoint & paintOffset)526 void RenderInline::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
527 {
528     ANNOTATE_GRAPHICS_CONTEXT(paintInfo, this);
529     m_lineBoxes.paint(this, paintInfo, paintOffset);
530 }
531 
532 template<typename GeneratorContext>
generateLineBoxRects(GeneratorContext & yield) const533 void RenderInline::generateLineBoxRects(GeneratorContext& yield) const
534 {
535     if (!alwaysCreateLineBoxes())
536         generateCulledLineBoxRects(yield, this);
537     else if (InlineFlowBox* curr = firstLineBox()) {
538         for (; curr; curr = curr->nextLineBox())
539             yield(FloatRect(curr->topLeft(), curr->size()));
540     } else
541         yield(FloatRect());
542 }
543 
544 template<typename GeneratorContext>
generateCulledLineBoxRects(GeneratorContext & yield,const RenderInline * container) const545 void RenderInline::generateCulledLineBoxRects(GeneratorContext& yield, const RenderInline* container) const
546 {
547     if (!culledInlineFirstLineBox()) {
548         yield(FloatRect());
549         return;
550     }
551 
552     bool isHorizontal = style()->isHorizontalWritingMode();
553 
554     for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) {
555         if (curr->isFloatingOrOutOfFlowPositioned())
556             continue;
557 
558         // We want to get the margin box in the inline direction, and then use our font ascent/descent in the block
559         // direction (aligned to the root box's baseline).
560         if (curr->isBox()) {
561             RenderBox* currBox = toRenderBox(curr);
562             if (currBox->inlineBoxWrapper()) {
563                 RootInlineBox* rootBox = currBox->inlineBoxWrapper()->root();
564                 int logicalTop = rootBox->logicalTop() + (rootBox->renderer()->style(rootBox->isFirstLineStyle())->font().fontMetrics().ascent() - container->style(rootBox->isFirstLineStyle())->font().fontMetrics().ascent());
565                 int logicalHeight = container->style(rootBox->isFirstLineStyle())->font().fontMetrics().height();
566                 if (isHorizontal)
567                     yield(FloatRect(currBox->inlineBoxWrapper()->x() - currBox->marginLeft(), logicalTop, currBox->width() + currBox->marginWidth(), logicalHeight));
568                 else
569                     yield(FloatRect(logicalTop, currBox->inlineBoxWrapper()->y() - currBox->marginTop(), logicalHeight, currBox->height() + currBox->marginHeight()));
570             }
571         } else if (curr->isRenderInline()) {
572             // If the child doesn't need line boxes either, then we can recur.
573             RenderInline* currInline = toRenderInline(curr);
574             if (!currInline->alwaysCreateLineBoxes())
575                 currInline->generateCulledLineBoxRects(yield, container);
576             else {
577                 for (InlineFlowBox* childLine = currInline->firstLineBox(); childLine; childLine = childLine->nextLineBox()) {
578                     RootInlineBox* rootBox = childLine->root();
579                     int logicalTop = rootBox->logicalTop() + (rootBox->renderer()->style(rootBox->isFirstLineStyle())->font().fontMetrics().ascent() - container->style(rootBox->isFirstLineStyle())->font().fontMetrics().ascent());
580                     int logicalHeight = container->style(rootBox->isFirstLineStyle())->font().fontMetrics().height();
581                     if (isHorizontal)
582                         yield(FloatRect(childLine->x() - childLine->marginLogicalLeft(),
583                             logicalTop,
584                             childLine->logicalWidth() + childLine->marginLogicalLeft() + childLine->marginLogicalRight(),
585                             logicalHeight));
586                     else
587                         yield(FloatRect(logicalTop,
588                             childLine->y() - childLine->marginLogicalLeft(),
589                             logicalHeight,
590                             childLine->logicalWidth() + childLine->marginLogicalLeft() + childLine->marginLogicalRight()));
591                 }
592             }
593         } else if (curr->isText()) {
594             RenderText* currText = toRenderText(curr);
595             for (InlineTextBox* childText = currText->firstTextBox(); childText; childText = childText->nextTextBox()) {
596                 RootInlineBox* rootBox = childText->root();
597                 int logicalTop = rootBox->logicalTop() + (rootBox->renderer()->style(rootBox->isFirstLineStyle())->font().fontMetrics().ascent() - container->style(rootBox->isFirstLineStyle())->font().fontMetrics().ascent());
598                 int logicalHeight = container->style(rootBox->isFirstLineStyle())->font().fontMetrics().height();
599                 if (isHorizontal)
600                     yield(FloatRect(childText->x(), logicalTop, childText->logicalWidth(), logicalHeight));
601                 else
602                     yield(FloatRect(logicalTop, childText->y(), logicalHeight, childText->logicalWidth()));
603             }
604         }
605     }
606 }
607 
608 namespace {
609 
610 class AbsoluteRectsGeneratorContext {
611 public:
AbsoluteRectsGeneratorContext(Vector<IntRect> & rects,const LayoutPoint & accumulatedOffset)612     AbsoluteRectsGeneratorContext(Vector<IntRect>& rects, const LayoutPoint& accumulatedOffset)
613         : m_rects(rects)
614         , m_accumulatedOffset(accumulatedOffset) { }
615 
operator ()(const FloatRect & rect)616     void operator()(const FloatRect& rect)
617     {
618         IntRect intRect = enclosingIntRect(rect);
619         intRect.move(m_accumulatedOffset.x(), m_accumulatedOffset.y());
620         m_rects.append(intRect);
621     }
622 private:
623     Vector<IntRect>& m_rects;
624     const LayoutPoint& m_accumulatedOffset;
625 };
626 
627 } // unnamed namespace
628 
absoluteRects(Vector<IntRect> & rects,const LayoutPoint & accumulatedOffset) const629 void RenderInline::absoluteRects(Vector<IntRect>& rects, const LayoutPoint& accumulatedOffset) const
630 {
631     AbsoluteRectsGeneratorContext context(rects, accumulatedOffset);
632     generateLineBoxRects(context);
633 
634     if (continuation()) {
635         if (continuation()->isBox()) {
636             RenderBox* box = toRenderBox(continuation());
637             continuation()->absoluteRects(rects, toLayoutPoint(accumulatedOffset - containingBlock()->location() + box->locationOffset()));
638         } else
639             continuation()->absoluteRects(rects, toLayoutPoint(accumulatedOffset - containingBlock()->location()));
640     }
641 }
642 
643 
644 namespace {
645 
646 class AbsoluteQuadsGeneratorContext {
647 public:
AbsoluteQuadsGeneratorContext(const RenderInline * renderer,Vector<FloatQuad> & quads)648     AbsoluteQuadsGeneratorContext(const RenderInline* renderer, Vector<FloatQuad>& quads)
649         : m_quads(quads)
650         , m_geometryMap()
651     {
652         m_geometryMap.pushMappingsToAncestor(renderer, 0);
653     }
654 
operator ()(const FloatRect & rect)655     void operator()(const FloatRect& rect)
656     {
657         m_quads.append(m_geometryMap.absoluteRect(rect));
658     }
659 private:
660     Vector<FloatQuad>& m_quads;
661     RenderGeometryMap m_geometryMap;
662 };
663 
664 } // unnamed namespace
665 
absoluteQuads(Vector<FloatQuad> & quads,bool * wasFixed) const666 void RenderInline::absoluteQuads(Vector<FloatQuad>& quads, bool* wasFixed) const
667 {
668     AbsoluteQuadsGeneratorContext context(this, quads);
669     generateLineBoxRects(context);
670 
671     if (continuation())
672         continuation()->absoluteQuads(quads, wasFixed);
673 }
674 
offsetLeft() const675 LayoutUnit RenderInline::offsetLeft() const
676 {
677     LayoutPoint topLeft;
678     if (InlineBox* firstBox = firstLineBoxIncludingCulling())
679         topLeft = flooredLayoutPoint(firstBox->topLeft());
680     return adjustedPositionRelativeToOffsetParent(topLeft).x();
681 }
682 
offsetTop() const683 LayoutUnit RenderInline::offsetTop() const
684 {
685     LayoutPoint topLeft;
686     if (InlineBox* firstBox = firstLineBoxIncludingCulling())
687         topLeft = flooredLayoutPoint(firstBox->topLeft());
688     return adjustedPositionRelativeToOffsetParent(topLeft).y();
689 }
690 
computeMargin(const RenderInline * renderer,const Length & margin)691 static LayoutUnit computeMargin(const RenderInline* renderer, const Length& margin)
692 {
693     if (margin.isAuto())
694         return 0;
695     if (margin.isFixed())
696         return margin.value();
697     if (margin.isPercent())
698         return minimumValueForLength(margin, max<LayoutUnit>(0, renderer->containingBlock()->availableLogicalWidth()));
699     if (margin.isViewportPercentage())
700         return valueForLength(margin, 0, renderer->view());
701     return 0;
702 }
703 
marginLeft() const704 LayoutUnit RenderInline::marginLeft() const
705 {
706     return computeMargin(this, style()->marginLeft());
707 }
708 
marginRight() const709 LayoutUnit RenderInline::marginRight() const
710 {
711     return computeMargin(this, style()->marginRight());
712 }
713 
marginTop() const714 LayoutUnit RenderInline::marginTop() const
715 {
716     return computeMargin(this, style()->marginTop());
717 }
718 
marginBottom() const719 LayoutUnit RenderInline::marginBottom() const
720 {
721     return computeMargin(this, style()->marginBottom());
722 }
723 
marginStart(const RenderStyle * otherStyle) const724 LayoutUnit RenderInline::marginStart(const RenderStyle* otherStyle) const
725 {
726     return computeMargin(this, style()->marginStartUsing(otherStyle ? otherStyle : style()));
727 }
728 
marginEnd(const RenderStyle * otherStyle) const729 LayoutUnit RenderInline::marginEnd(const RenderStyle* otherStyle) const
730 {
731     return computeMargin(this, style()->marginEndUsing(otherStyle ? otherStyle : style()));
732 }
733 
marginBefore(const RenderStyle * otherStyle) const734 LayoutUnit RenderInline::marginBefore(const RenderStyle* otherStyle) const
735 {
736     return computeMargin(this, style()->marginBeforeUsing(otherStyle ? otherStyle : style()));
737 }
738 
marginAfter(const RenderStyle * otherStyle) const739 LayoutUnit RenderInline::marginAfter(const RenderStyle* otherStyle) const
740 {
741     return computeMargin(this, style()->marginAfterUsing(otherStyle ? otherStyle : style()));
742 }
743 
renderName() const744 const char* RenderInline::renderName() const
745 {
746     if (isRelPositioned())
747         return "RenderInline (relative positioned)";
748     if (isStickyPositioned())
749         return "RenderInline (sticky positioned)";
750     // FIXME: Temporary hack while the new generated content system is being implemented.
751     if (isPseudoElement())
752         return "RenderInline (generated)";
753     if (isAnonymous())
754         return "RenderInline (generated)";
755     return "RenderInline";
756 }
757 
nodeAtPoint(const HitTestRequest & request,HitTestResult & result,const HitTestLocation & locationInContainer,const LayoutPoint & accumulatedOffset,HitTestAction hitTestAction)758 bool RenderInline::nodeAtPoint(const HitTestRequest& request, HitTestResult& result,
759                                 const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction hitTestAction)
760 {
761     return m_lineBoxes.hitTest(this, request, result, locationInContainer, accumulatedOffset, hitTestAction);
762 }
763 
764 namespace {
765 
766 class HitTestCulledInlinesGeneratorContext {
767 public:
HitTestCulledInlinesGeneratorContext(Region & region,const HitTestLocation & location)768     HitTestCulledInlinesGeneratorContext(Region& region, const HitTestLocation& location) : m_intersected(false), m_region(region), m_location(location) { }
operator ()(const FloatRect & rect)769     void operator()(const FloatRect& rect)
770     {
771         m_intersected = m_intersected || m_location.intersects(rect);
772         m_region.unite(enclosingIntRect(rect));
773     }
intersected() const774     bool intersected() const { return m_intersected; }
775 private:
776     bool m_intersected;
777     Region& m_region;
778     const HitTestLocation& m_location;
779 };
780 
781 } // unnamed namespace
782 
hitTestCulledInline(const HitTestRequest & request,HitTestResult & result,const HitTestLocation & locationInContainer,const LayoutPoint & accumulatedOffset)783 bool RenderInline::hitTestCulledInline(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset)
784 {
785     ASSERT(result.isRectBasedTest() && !alwaysCreateLineBoxes());
786     if (!visibleToHitTestRequest(request))
787         return false;
788 
789     HitTestLocation tmpLocation(locationInContainer, -toLayoutSize(accumulatedOffset));
790 
791     Region regionResult;
792     HitTestCulledInlinesGeneratorContext context(regionResult, tmpLocation);
793     generateCulledLineBoxRects(context, this);
794 
795     if (context.intersected()) {
796         updateHitTestResult(result, tmpLocation.point());
797         // We can not use addNodeToRectBasedTestResult to determine if we fully enclose the hit-test area
798         // because it can only handle rectangular targets.
799         result.addNodeToRectBasedTestResult(node(), request, locationInContainer);
800         return regionResult.contains(tmpLocation.boundingBox());
801     }
802     return false;
803 }
804 
positionForPoint(const LayoutPoint & point)805 PositionWithAffinity RenderInline::positionForPoint(const LayoutPoint& point)
806 {
807     // FIXME: Does not deal with relative or sticky positioned inlines (should it?)
808     RenderBlock* cb = containingBlock();
809     if (firstLineBox()) {
810         // This inline actually has a line box.  We must have clicked in the border/padding of one of these boxes.  We
811         // should try to find a result by asking our containing block.
812         return cb->positionForPoint(point);
813     }
814 
815     // Translate the coords from the pre-anonymous block to the post-anonymous block.
816     LayoutPoint parentBlockPoint = cb->location() + point;
817     RenderBoxModelObject* c = continuation();
818     while (c) {
819         RenderBox* contBlock = c->isInline() ? c->containingBlock() : toRenderBlock(c);
820         if (c->isInline() || c->firstChild())
821             return c->positionForPoint(parentBlockPoint - contBlock->locationOffset());
822         c = toRenderBlock(c)->inlineElementContinuation();
823     }
824 
825     return RenderBoxModelObject::positionForPoint(point);
826 }
827 
828 namespace {
829 
830 class LinesBoundingBoxGeneratorContext {
831 public:
LinesBoundingBoxGeneratorContext(FloatRect & rect)832     LinesBoundingBoxGeneratorContext(FloatRect& rect) : m_rect(rect) { }
operator ()(const FloatRect & rect)833     void operator()(const FloatRect& rect)
834     {
835         m_rect.uniteIfNonZero(rect);
836     }
837 private:
838     FloatRect& m_rect;
839 };
840 
841 } // unnamed namespace
842 
linesBoundingBox() const843 IntRect RenderInline::linesBoundingBox() const
844 {
845     if (!alwaysCreateLineBoxes()) {
846         ASSERT(!firstLineBox());
847         FloatRect floatResult;
848         LinesBoundingBoxGeneratorContext context(floatResult);
849         generateCulledLineBoxRects(context, this);
850         return enclosingIntRect(floatResult);
851     }
852 
853     IntRect result;
854 
855     // 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
856     // 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
857     // builds and help us someday figure out why.  We also put in a redundant check of lastLineBox() to avoid the crash for now.
858     ASSERT(!firstLineBox() == !lastLineBox());  // Either both are null or both exist.
859     if (firstLineBox() && lastLineBox()) {
860         // Return the width of the minimal left side and the maximal right side.
861         float logicalLeftSide = 0;
862         float logicalRightSide = 0;
863         for (InlineFlowBox* curr = firstLineBox(); curr; curr = curr->nextLineBox()) {
864             if (curr == firstLineBox() || curr->logicalLeft() < logicalLeftSide)
865                 logicalLeftSide = curr->logicalLeft();
866             if (curr == firstLineBox() || curr->logicalRight() > logicalRightSide)
867                 logicalRightSide = curr->logicalRight();
868         }
869 
870         bool isHorizontal = style()->isHorizontalWritingMode();
871 
872         float x = isHorizontal ? logicalLeftSide : firstLineBox()->x();
873         float y = isHorizontal ? firstLineBox()->y() : logicalLeftSide;
874         float width = isHorizontal ? logicalRightSide - logicalLeftSide : lastLineBox()->logicalBottom() - x;
875         float height = isHorizontal ? lastLineBox()->logicalBottom() - y : logicalRightSide - logicalLeftSide;
876         result = enclosingIntRect(FloatRect(x, y, width, height));
877     }
878 
879     return result;
880 }
881 
culledInlineFirstLineBox() const882 InlineBox* RenderInline::culledInlineFirstLineBox() const
883 {
884     for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) {
885         if (curr->isFloatingOrOutOfFlowPositioned())
886             continue;
887 
888         // We want to get the margin box in the inline direction, and then use our font ascent/descent in the block
889         // direction (aligned to the root box's baseline).
890         if (curr->isBox())
891             return toRenderBox(curr)->inlineBoxWrapper();
892         if (curr->isRenderInline()) {
893             RenderInline* currInline = toRenderInline(curr);
894             InlineBox* result = currInline->firstLineBoxIncludingCulling();
895             if (result)
896                 return result;
897         } else if (curr->isText()) {
898             RenderText* currText = toRenderText(curr);
899             if (currText->firstTextBox())
900                 return currText->firstTextBox();
901         }
902     }
903     return 0;
904 }
905 
culledInlineLastLineBox() const906 InlineBox* RenderInline::culledInlineLastLineBox() const
907 {
908     for (RenderObject* curr = lastChild(); curr; curr = curr->previousSibling()) {
909         if (curr->isFloatingOrOutOfFlowPositioned())
910             continue;
911 
912         // We want to get the margin box in the inline direction, and then use our font ascent/descent in the block
913         // direction (aligned to the root box's baseline).
914         if (curr->isBox())
915             return toRenderBox(curr)->inlineBoxWrapper();
916         if (curr->isRenderInline()) {
917             RenderInline* currInline = toRenderInline(curr);
918             InlineBox* result = currInline->lastLineBoxIncludingCulling();
919             if (result)
920                 return result;
921         } else if (curr->isText()) {
922             RenderText* currText = toRenderText(curr);
923             if (currText->lastTextBox())
924                 return currText->lastTextBox();
925         }
926     }
927     return 0;
928 }
929 
culledInlineVisualOverflowBoundingBox() const930 LayoutRect RenderInline::culledInlineVisualOverflowBoundingBox() const
931 {
932     FloatRect floatResult;
933     LinesBoundingBoxGeneratorContext context(floatResult);
934     generateCulledLineBoxRects(context, this);
935     LayoutRect result(enclosingLayoutRect(floatResult));
936     bool isHorizontal = style()->isHorizontalWritingMode();
937     for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) {
938         if (curr->isFloatingOrOutOfFlowPositioned())
939             continue;
940 
941         // For overflow we just have to propagate by hand and recompute it all.
942         if (curr->isBox()) {
943             RenderBox* currBox = toRenderBox(curr);
944             if (!currBox->hasSelfPaintingLayer() && currBox->inlineBoxWrapper()) {
945                 LayoutRect logicalRect = currBox->logicalVisualOverflowRectForPropagation(style());
946                 if (isHorizontal) {
947                     logicalRect.moveBy(currBox->location());
948                     result.uniteIfNonZero(logicalRect);
949                 } else {
950                     logicalRect.moveBy(currBox->location());
951                     result.uniteIfNonZero(logicalRect.transposedRect());
952                 }
953             }
954         } else if (curr->isRenderInline()) {
955             // If the child doesn't need line boxes either, then we can recur.
956             RenderInline* currInline = toRenderInline(curr);
957             if (!currInline->alwaysCreateLineBoxes())
958                 result.uniteIfNonZero(currInline->culledInlineVisualOverflowBoundingBox());
959             else if (!currInline->hasSelfPaintingLayer())
960                 result.uniteIfNonZero(currInline->linesVisualOverflowBoundingBox());
961         } else if (curr->isText()) {
962             // FIXME; Overflow from text boxes is lost. We will need to cache this information in
963             // InlineTextBoxes.
964             RenderText* currText = toRenderText(curr);
965             result.uniteIfNonZero(currText->linesVisualOverflowBoundingBox());
966         }
967     }
968     return result;
969 }
970 
linesVisualOverflowBoundingBox() const971 LayoutRect RenderInline::linesVisualOverflowBoundingBox() const
972 {
973     if (!alwaysCreateLineBoxes())
974         return culledInlineVisualOverflowBoundingBox();
975 
976     if (!firstLineBox() || !lastLineBox())
977         return LayoutRect();
978 
979     // Return the width of the minimal left side and the maximal right side.
980     LayoutUnit logicalLeftSide = LayoutUnit::max();
981     LayoutUnit logicalRightSide = LayoutUnit::min();
982     for (InlineFlowBox* curr = firstLineBox(); curr; curr = curr->nextLineBox()) {
983         logicalLeftSide = min(logicalLeftSide, curr->logicalLeftVisualOverflow());
984         logicalRightSide = max(logicalRightSide, curr->logicalRightVisualOverflow());
985     }
986 
987     RootInlineBox* firstRootBox = firstLineBox()->root();
988     RootInlineBox* lastRootBox = lastLineBox()->root();
989 
990     LayoutUnit logicalTop = firstLineBox()->logicalTopVisualOverflow(firstRootBox->lineTop());
991     LayoutUnit logicalWidth = logicalRightSide - logicalLeftSide;
992     LayoutUnit logicalHeight = lastLineBox()->logicalBottomVisualOverflow(lastRootBox->lineBottom()) - logicalTop;
993 
994     LayoutRect rect(logicalLeftSide, logicalTop, logicalWidth, logicalHeight);
995     if (!style()->isHorizontalWritingMode())
996         rect = rect.transposedRect();
997     return rect;
998 }
999 
clippedOverflowRectForRepaint(const RenderLayerModelObject * repaintContainer) const1000 LayoutRect RenderInline::clippedOverflowRectForRepaint(const RenderLayerModelObject* repaintContainer) const
1001 {
1002     ASSERT(!view() || !view()->layoutStateEnabled() || LayoutRectRecorder::shouldRecordLayoutRects());
1003 
1004     if (!firstLineBoxIncludingCulling() && !continuation())
1005         return LayoutRect();
1006 
1007     LayoutRect repaintRect(linesVisualOverflowBoundingBox());
1008     bool hitRepaintContainer = false;
1009 
1010     // We need to add in the in-flow position offsets of any inlines (including us) up to our
1011     // containing block.
1012     RenderBlock* cb = containingBlock();
1013     for (const RenderObject* inlineFlow = this; inlineFlow && inlineFlow->isRenderInline() && inlineFlow != cb;
1014          inlineFlow = inlineFlow->parent()) {
1015          if (inlineFlow == repaintContainer) {
1016             hitRepaintContainer = true;
1017             break;
1018         }
1019         if (inlineFlow->style()->hasInFlowPosition() && inlineFlow->hasLayer())
1020             repaintRect.move(toRenderInline(inlineFlow)->layer()->offsetForInFlowPosition());
1021     }
1022 
1023     LayoutUnit outlineSize = style()->outlineSize();
1024     repaintRect.inflate(outlineSize);
1025 
1026     if (hitRepaintContainer || !cb)
1027         return repaintRect;
1028 
1029     if (cb->hasColumns())
1030         cb->adjustRectForColumns(repaintRect);
1031 
1032     if (cb->hasOverflowClip())
1033         cb->applyCachedClipAndScrollOffsetForRepaint(repaintRect);
1034 
1035     cb->computeRectForRepaint(repaintContainer, repaintRect);
1036 
1037     if (outlineSize) {
1038         for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) {
1039             if (!curr->isText())
1040                 repaintRect.unite(curr->rectWithOutlineForRepaint(repaintContainer, outlineSize));
1041         }
1042 
1043         if (continuation() && !continuation()->isInline() && continuation()->parent())
1044             repaintRect.unite(continuation()->rectWithOutlineForRepaint(repaintContainer, outlineSize));
1045     }
1046 
1047     return repaintRect;
1048 }
1049 
rectWithOutlineForRepaint(const RenderLayerModelObject * repaintContainer,LayoutUnit outlineWidth) const1050 LayoutRect RenderInline::rectWithOutlineForRepaint(const RenderLayerModelObject* repaintContainer, LayoutUnit outlineWidth) const
1051 {
1052     LayoutRect r(RenderBoxModelObject::rectWithOutlineForRepaint(repaintContainer, outlineWidth));
1053     for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) {
1054         if (!curr->isText())
1055             r.unite(curr->rectWithOutlineForRepaint(repaintContainer, outlineWidth));
1056     }
1057     return r;
1058 }
1059 
computeRectForRepaint(const RenderLayerModelObject * repaintContainer,LayoutRect & rect,bool fixed) const1060 void RenderInline::computeRectForRepaint(const RenderLayerModelObject* repaintContainer, LayoutRect& rect, bool fixed) const
1061 {
1062     if (RenderView* v = view()) {
1063         // LayoutState is only valid for root-relative repainting
1064         if (v->layoutStateEnabled() && !repaintContainer) {
1065             LayoutState* layoutState = v->layoutState();
1066             if (style()->hasInFlowPosition() && layer())
1067                 rect.move(layer()->offsetForInFlowPosition());
1068             rect.move(layoutState->m_paintOffset);
1069             if (layoutState->m_clipped)
1070                 rect.intersect(layoutState->m_clipRect);
1071             return;
1072         }
1073     }
1074 
1075     if (repaintContainer == this)
1076         return;
1077 
1078     bool containerSkipped;
1079     RenderObject* o = container(repaintContainer, &containerSkipped);
1080     if (!o)
1081         return;
1082 
1083     LayoutPoint topLeft = rect.location();
1084 
1085     if (o->isRenderBlockFlow() && !style()->hasOutOfFlowPosition()) {
1086         RenderBlock* cb = toRenderBlock(o);
1087         if (cb->hasColumns()) {
1088             LayoutRect repaintRect(topLeft, rect.size());
1089             cb->adjustRectForColumns(repaintRect);
1090             topLeft = repaintRect.location();
1091             rect = repaintRect;
1092         }
1093     }
1094 
1095     if (style()->hasInFlowPosition() && layer()) {
1096         // Apply the in-flow position offset when invalidating a rectangle. The layer
1097         // is translated, but the render box isn't, so we need to do this to get the
1098         // right dirty rect. Since this is called from RenderObject::setStyle, the relative or sticky position
1099         // flag on the RenderObject has been cleared, so use the one on the style().
1100         topLeft += layer()->offsetForInFlowPosition();
1101     }
1102 
1103     // FIXME: We ignore the lightweight clipping rect that controls use, since if |o| is in mid-layout,
1104     // its controlClipRect will be wrong. For overflow clip we use the values cached by the layer.
1105     rect.setLocation(topLeft);
1106     if (o->hasOverflowClip()) {
1107         RenderBox* containerBox = toRenderBox(o);
1108         containerBox->applyCachedClipAndScrollOffsetForRepaint(rect);
1109         if (rect.isEmpty())
1110             return;
1111     }
1112 
1113     if (containerSkipped) {
1114         // If the repaintContainer is below o, then we need to map the rect into repaintContainer's coordinates.
1115         LayoutSize containerOffset = repaintContainer->offsetFromAncestorContainer(o);
1116         rect.move(-containerOffset);
1117         return;
1118     }
1119 
1120     o->computeRectForRepaint(repaintContainer, rect, fixed);
1121 }
1122 
offsetFromContainer(RenderObject * container,const LayoutPoint & point,bool * offsetDependsOnPoint) const1123 LayoutSize RenderInline::offsetFromContainer(RenderObject* container, const LayoutPoint& point, bool* offsetDependsOnPoint) const
1124 {
1125     ASSERT(container == this->container());
1126 
1127     LayoutSize offset;
1128     if (isInFlowPositioned())
1129         offset += offsetForInFlowPosition();
1130 
1131     container->adjustForColumns(offset, point);
1132 
1133     if (container->hasOverflowClip())
1134         offset -= toRenderBox(container)->scrolledContentOffset();
1135 
1136     if (offsetDependsOnPoint) {
1137         *offsetDependsOnPoint = container->hasColumns()
1138             || (container->isBox() && container->style()->isFlippedBlocksWritingMode())
1139             || container->isRenderFlowThread();
1140     }
1141 
1142     return offset;
1143 }
1144 
mapLocalToContainer(const RenderLayerModelObject * repaintContainer,TransformState & transformState,MapCoordinatesFlags mode,bool * wasFixed) const1145 void RenderInline::mapLocalToContainer(const RenderLayerModelObject* repaintContainer, TransformState& transformState, MapCoordinatesFlags mode, bool* wasFixed) const
1146 {
1147     if (repaintContainer == this)
1148         return;
1149 
1150     if (RenderView *v = view()) {
1151         if (v->layoutStateEnabled() && !repaintContainer) {
1152             LayoutState* layoutState = v->layoutState();
1153             LayoutSize offset = layoutState->m_paintOffset;
1154             if (style()->hasInFlowPosition() && layer())
1155                 offset += layer()->offsetForInFlowPosition();
1156             transformState.move(offset);
1157             return;
1158         }
1159     }
1160 
1161     bool containerSkipped;
1162     RenderObject* o = container(repaintContainer, &containerSkipped);
1163     if (!o)
1164         return;
1165 
1166     if (mode & ApplyContainerFlip && o->isBox()) {
1167         if (o->style()->isFlippedBlocksWritingMode()) {
1168             IntPoint centerPoint = roundedIntPoint(transformState.mappedPoint());
1169             transformState.move(toRenderBox(o)->flipForWritingModeIncludingColumns(centerPoint) - centerPoint);
1170         }
1171         mode &= ~ApplyContainerFlip;
1172     }
1173 
1174     LayoutSize containerOffset = offsetFromContainer(o, roundedLayoutPoint(transformState.mappedPoint()));
1175 
1176     bool preserve3D = mode & UseTransforms && (o->style()->preserves3D() || style()->preserves3D());
1177     if (mode & UseTransforms && shouldUseTransformFromContainer(o)) {
1178         TransformationMatrix t;
1179         getTransformFromContainer(o, containerOffset, t);
1180         transformState.applyTransform(t, preserve3D ? TransformState::AccumulateTransform : TransformState::FlattenTransform);
1181     } else
1182         transformState.move(containerOffset.width(), containerOffset.height(), preserve3D ? TransformState::AccumulateTransform : TransformState::FlattenTransform);
1183 
1184     if (containerSkipped) {
1185         // There can't be a transform between repaintContainer and o, because transforms create containers, so it should be safe
1186         // to just subtract the delta between the repaintContainer and o.
1187         LayoutSize containerOffset = repaintContainer->offsetFromAncestorContainer(o);
1188         transformState.move(-containerOffset.width(), -containerOffset.height(), preserve3D ? TransformState::AccumulateTransform : TransformState::FlattenTransform);
1189         return;
1190     }
1191 
1192     o->mapLocalToContainer(repaintContainer, transformState, mode, wasFixed);
1193 }
1194 
updateDragState(bool dragOn)1195 void RenderInline::updateDragState(bool dragOn)
1196 {
1197     RenderBoxModelObject::updateDragState(dragOn);
1198     if (continuation())
1199         continuation()->updateDragState(dragOn);
1200 }
1201 
childBecameNonInline(RenderObject * child)1202 void RenderInline::childBecameNonInline(RenderObject* child)
1203 {
1204     // We have to split the parent flow.
1205     RenderBlock* newBox = containingBlock()->createAnonymousBlock();
1206     RenderBoxModelObject* oldContinuation = continuation();
1207     setContinuation(newBox);
1208     RenderObject* beforeChild = child->nextSibling();
1209     children()->removeChildNode(this, child);
1210     splitFlow(beforeChild, newBox, child, oldContinuation);
1211 }
1212 
updateHitTestResult(HitTestResult & result,const LayoutPoint & point)1213 void RenderInline::updateHitTestResult(HitTestResult& result, const LayoutPoint& point)
1214 {
1215     if (result.innerNode())
1216         return;
1217 
1218     Node* n = node();
1219     LayoutPoint localPoint(point);
1220     if (n) {
1221         if (isInlineElementContinuation()) {
1222             // We're in the continuation of a split inline.  Adjust our local point to be in the coordinate space
1223             // of the principal renderer's containing block.  This will end up being the innerNonSharedNode.
1224             RenderBlock* firstBlock = n->renderer()->containingBlock();
1225 
1226             // Get our containing block.
1227             RenderBox* block = containingBlock();
1228             localPoint.moveBy(block->location() - firstBlock->locationOffset());
1229         }
1230 
1231         result.setInnerNode(n);
1232         if (!result.innerNonSharedNode())
1233             result.setInnerNonSharedNode(n);
1234         result.setLocalPoint(localPoint);
1235     }
1236 }
1237 
dirtyLineBoxes(bool fullLayout)1238 void RenderInline::dirtyLineBoxes(bool fullLayout)
1239 {
1240     if (fullLayout) {
1241         m_lineBoxes.deleteLineBoxes();
1242         return;
1243     }
1244 
1245     if (!alwaysCreateLineBoxes()) {
1246         // We have to grovel into our children in order to dirty the appropriate lines.
1247         for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) {
1248             if (curr->isFloatingOrOutOfFlowPositioned())
1249                 continue;
1250             if (curr->isBox() && !curr->needsLayout()) {
1251                 RenderBox* currBox = toRenderBox(curr);
1252                 if (currBox->inlineBoxWrapper())
1253                     currBox->inlineBoxWrapper()->root()->markDirty();
1254             } else if (!curr->selfNeedsLayout()) {
1255                 if (curr->isRenderInline()) {
1256                     RenderInline* currInline = toRenderInline(curr);
1257                     for (InlineFlowBox* childLine = currInline->firstLineBox(); childLine; childLine = childLine->nextLineBox())
1258                         childLine->root()->markDirty();
1259                 } else if (curr->isText()) {
1260                     RenderText* currText = toRenderText(curr);
1261                     for (InlineTextBox* childText = currText->firstTextBox(); childText; childText = childText->nextTextBox())
1262                         childText->root()->markDirty();
1263                 }
1264             }
1265         }
1266     } else
1267         m_lineBoxes.dirtyLineBoxes();
1268 }
1269 
deleteLineBoxTree()1270 void RenderInline::deleteLineBoxTree()
1271 {
1272     m_lineBoxes.deleteLineBoxTree();
1273 }
1274 
createInlineFlowBox()1275 InlineFlowBox* RenderInline::createInlineFlowBox()
1276 {
1277     return new InlineFlowBox(this);
1278 }
1279 
createAndAppendInlineFlowBox()1280 InlineFlowBox* RenderInline::createAndAppendInlineFlowBox()
1281 {
1282     setAlwaysCreateLineBoxes();
1283     InlineFlowBox* flowBox = createInlineFlowBox();
1284     m_lineBoxes.appendLineBox(flowBox);
1285     return flowBox;
1286 }
1287 
lineHeight(bool firstLine,LineDirectionMode,LinePositionMode) const1288 LayoutUnit RenderInline::lineHeight(bool firstLine, LineDirectionMode /*direction*/, LinePositionMode /*linePositionMode*/) const
1289 {
1290     if (firstLine && document().styleEngine()->usesFirstLineRules()) {
1291         RenderStyle* s = style(firstLine);
1292         if (s != style())
1293             return s->computedLineHeight(view());
1294     }
1295 
1296     return style()->computedLineHeight(view());
1297 }
1298 
baselinePosition(FontBaseline baselineType,bool firstLine,LineDirectionMode direction,LinePositionMode linePositionMode) const1299 int RenderInline::baselinePosition(FontBaseline baselineType, bool firstLine, LineDirectionMode direction, LinePositionMode linePositionMode) const
1300 {
1301     ASSERT(linePositionMode == PositionOnContainingLine);
1302     const FontMetrics& fontMetrics = style(firstLine)->fontMetrics();
1303     return fontMetrics.ascent(baselineType) + (lineHeight(firstLine, direction, linePositionMode) - fontMetrics.height()) / 2;
1304 }
1305 
offsetForInFlowPositionedInline(const RenderBox * child) const1306 LayoutSize RenderInline::offsetForInFlowPositionedInline(const RenderBox* child) const
1307 {
1308     // FIXME: This function isn't right with mixed writing modes.
1309 
1310     ASSERT(isInFlowPositioned());
1311     if (!isInFlowPositioned())
1312         return LayoutSize();
1313 
1314     // When we have an enclosing relpositioned inline, we need to add in the offset of the first line
1315     // box from the rest of the content, but only in the cases where we know we're positioned
1316     // relative to the inline itself.
1317 
1318     LayoutSize logicalOffset;
1319     LayoutUnit inlinePosition;
1320     LayoutUnit blockPosition;
1321     if (firstLineBox()) {
1322         inlinePosition = LayoutUnit::fromFloatRound(firstLineBox()->logicalLeft());
1323         blockPosition = firstLineBox()->logicalTop();
1324     } else {
1325         inlinePosition = layer()->staticInlinePosition();
1326         blockPosition = layer()->staticBlockPosition();
1327     }
1328 
1329     if (!child->style()->hasStaticInlinePosition(style()->isHorizontalWritingMode()))
1330         logicalOffset.setWidth(inlinePosition);
1331 
1332     // This is not terribly intuitive, but we have to match other browsers.  Despite being a block display type inside
1333     // an inline, we still keep our x locked to the left of the relative positioned inline.  Arguably the correct
1334     // behavior would be to go flush left to the block that contains the inline, but that isn't what other browsers
1335     // do.
1336     else if (!child->style()->isOriginalDisplayInlineType())
1337         // Avoid adding in the left border/padding of the containing block twice.  Subtract it out.
1338         logicalOffset.setWidth(inlinePosition - child->containingBlock()->borderAndPaddingLogicalLeft());
1339 
1340     if (!child->style()->hasStaticBlockPosition(style()->isHorizontalWritingMode()))
1341         logicalOffset.setHeight(blockPosition);
1342 
1343     return style()->isHorizontalWritingMode() ? logicalOffset : logicalOffset.transposedSize();
1344 }
1345 
imageChanged(WrappedImagePtr,const IntRect *)1346 void RenderInline::imageChanged(WrappedImagePtr, const IntRect*)
1347 {
1348     if (!parent())
1349         return;
1350 
1351     // FIXME: We can do better.
1352     repaint();
1353 }
1354 
addFocusRingRects(Vector<IntRect> & rects,const LayoutPoint & additionalOffset,const RenderLayerModelObject * paintContainer)1355 void RenderInline::addFocusRingRects(Vector<IntRect>& rects, const LayoutPoint& additionalOffset, const RenderLayerModelObject* paintContainer)
1356 {
1357     AbsoluteRectsGeneratorContext context(rects, additionalOffset);
1358     generateLineBoxRects(context);
1359 
1360     for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) {
1361         if (!curr->isText() && !curr->isListMarker()) {
1362             FloatPoint pos(additionalOffset);
1363             // FIXME: This doesn't work correctly with transforms.
1364             if (curr->hasLayer())
1365                 pos = curr->localToContainerPoint(FloatPoint(), paintContainer);
1366             else if (curr->isBox())
1367                 pos.move(toRenderBox(curr)->locationOffset());
1368             curr->addFocusRingRects(rects, flooredIntPoint(pos), paintContainer);
1369         }
1370     }
1371 
1372     if (continuation()) {
1373         if (continuation()->isInline())
1374             continuation()->addFocusRingRects(rects, flooredLayoutPoint(additionalOffset + continuation()->containingBlock()->location() - containingBlock()->location()), paintContainer);
1375         else
1376             continuation()->addFocusRingRects(rects, flooredLayoutPoint(additionalOffset + toRenderBox(continuation())->location() - containingBlock()->location()), paintContainer);
1377     }
1378 }
1379 
1380 namespace {
1381 
1382 class AbsoluteLayoutRectsGeneratorContext {
1383 public:
AbsoluteLayoutRectsGeneratorContext(Vector<LayoutRect> & rects,const LayoutPoint & accumulatedOffset)1384     AbsoluteLayoutRectsGeneratorContext(Vector<LayoutRect>& rects, const LayoutPoint& accumulatedOffset)
1385         : m_rects(rects)
1386         , m_accumulatedOffset(accumulatedOffset) { }
1387 
operator ()(const FloatRect & rect)1388     void operator()(const FloatRect& rect)
1389     {
1390         LayoutRect layoutRect(rect);
1391         layoutRect.move(m_accumulatedOffset.x(), m_accumulatedOffset.y());
1392         m_rects.append(layoutRect);
1393     }
1394 private:
1395     Vector<LayoutRect>& m_rects;
1396     const LayoutPoint& m_accumulatedOffset;
1397 };
1398 
1399 }
1400 
computeSelfHitTestRects(Vector<LayoutRect> & rects,const LayoutPoint & layerOffset) const1401 void RenderInline::computeSelfHitTestRects(Vector<LayoutRect>& rects, const LayoutPoint& layerOffset) const
1402 {
1403     AbsoluteLayoutRectsGeneratorContext context(rects, layerOffset);
1404     generateLineBoxRects(context);
1405 }
1406 
paintOutline(PaintInfo & paintInfo,const LayoutPoint & paintOffset)1407 void RenderInline::paintOutline(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
1408 {
1409     if (!hasOutline())
1410         return;
1411 
1412     RenderStyle* styleToUse = style();
1413     if (styleToUse->outlineStyleIsAuto() || hasOutlineAnnotation()) {
1414         if (RenderTheme::theme().shouldDrawDefaultFocusRing(this)) {
1415             // Only paint the focus ring by hand if the theme isn't able to draw the focus ring.
1416             paintFocusRing(paintInfo, paintOffset, styleToUse);
1417         }
1418     }
1419 
1420     GraphicsContext* graphicsContext = paintInfo.context;
1421     if (graphicsContext->paintingDisabled())
1422         return;
1423 
1424     if (styleToUse->outlineStyleIsAuto() || styleToUse->outlineStyle() == BNONE)
1425         return;
1426 
1427     Vector<LayoutRect> rects;
1428 
1429     rects.append(LayoutRect());
1430     for (InlineFlowBox* curr = firstLineBox(); curr; curr = curr->nextLineBox()) {
1431         RootInlineBox* root = curr->root();
1432         LayoutUnit top = max<LayoutUnit>(root->lineTop(), curr->logicalTop());
1433         LayoutUnit bottom = min<LayoutUnit>(root->lineBottom(), curr->logicalBottom());
1434         rects.append(LayoutRect(curr->x(), top, curr->logicalWidth(), bottom - top));
1435     }
1436     rects.append(LayoutRect());
1437 
1438     Color outlineColor = resolveColor(styleToUse, CSSPropertyOutlineColor);
1439     bool useTransparencyLayer = outlineColor.hasAlpha();
1440     if (useTransparencyLayer) {
1441         graphicsContext->beginTransparencyLayer(static_cast<float>(outlineColor.alpha()) / 255);
1442         outlineColor = Color(outlineColor.red(), outlineColor.green(), outlineColor.blue());
1443     }
1444 
1445     for (unsigned i = 1; i < rects.size() - 1; i++)
1446         paintOutlineForLine(graphicsContext, paintOffset, rects.at(i - 1), rects.at(i), rects.at(i + 1), outlineColor);
1447 
1448     if (useTransparencyLayer)
1449         graphicsContext->endLayer();
1450 }
1451 
paintOutlineForLine(GraphicsContext * graphicsContext,const LayoutPoint & paintOffset,const LayoutRect & lastline,const LayoutRect & thisline,const LayoutRect & nextline,const Color outlineColor)1452 void RenderInline::paintOutlineForLine(GraphicsContext* graphicsContext, const LayoutPoint& paintOffset,
1453                                        const LayoutRect& lastline, const LayoutRect& thisline, const LayoutRect& nextline,
1454                                        const Color outlineColor)
1455 {
1456     RenderStyle* styleToUse = style();
1457     int outlineWidth = styleToUse->outlineWidth();
1458     EBorderStyle outlineStyle = styleToUse->outlineStyle();
1459 
1460     bool antialias = shouldAntialiasLines(graphicsContext);
1461 
1462     int offset = style()->outlineOffset();
1463 
1464     LayoutRect box(LayoutPoint(paintOffset.x() + thisline.x() - offset, paintOffset.y() + thisline.y() - offset),
1465         LayoutSize(thisline.width() + offset, thisline.height() + offset));
1466 
1467     IntRect pixelSnappedBox = pixelSnappedIntRect(box);
1468     IntRect pixelSnappedLastLine = pixelSnappedIntRect(paintOffset.x() + lastline.x(), 0, lastline.width(), 0);
1469     IntRect pixelSnappedNextLine = pixelSnappedIntRect(paintOffset.x() + nextline.x(), 0, nextline.width(), 0);
1470 
1471     // left edge
1472     drawLineForBoxSide(graphicsContext,
1473         pixelSnappedBox.x() - outlineWidth,
1474         pixelSnappedBox.y() - (lastline.isEmpty() || thisline.x() < lastline.x() || (lastline.maxX() - 1) <= thisline.x() ? outlineWidth : 0),
1475         pixelSnappedBox.x(),
1476         pixelSnappedBox.maxY() + (nextline.isEmpty() || thisline.x() <= nextline.x() || (nextline.maxX() - 1) <= thisline.x() ? outlineWidth : 0),
1477         BSLeft,
1478         outlineColor, outlineStyle,
1479         (lastline.isEmpty() || thisline.x() < lastline.x() || (lastline.maxX() - 1) <= thisline.x() ? outlineWidth : -outlineWidth),
1480         (nextline.isEmpty() || thisline.x() <= nextline.x() || (nextline.maxX() - 1) <= thisline.x() ? outlineWidth : -outlineWidth),
1481         antialias);
1482 
1483     // right edge
1484     drawLineForBoxSide(graphicsContext,
1485         pixelSnappedBox.maxX(),
1486         pixelSnappedBox.y() - (lastline.isEmpty() || lastline.maxX() < thisline.maxX() || (thisline.maxX() - 1) <= lastline.x() ? outlineWidth : 0),
1487         pixelSnappedBox.maxX() + outlineWidth,
1488         pixelSnappedBox.maxY() + (nextline.isEmpty() || nextline.maxX() <= thisline.maxX() || (thisline.maxX() - 1) <= nextline.x() ? outlineWidth : 0),
1489         BSRight,
1490         outlineColor, outlineStyle,
1491         (lastline.isEmpty() || lastline.maxX() < thisline.maxX() || (thisline.maxX() - 1) <= lastline.x() ? outlineWidth : -outlineWidth),
1492         (nextline.isEmpty() || nextline.maxX() <= thisline.maxX() || (thisline.maxX() - 1) <= nextline.x() ? outlineWidth : -outlineWidth),
1493         antialias);
1494     // upper edge
1495     if (thisline.x() < lastline.x())
1496         drawLineForBoxSide(graphicsContext,
1497             pixelSnappedBox.x() - outlineWidth,
1498             pixelSnappedBox.y() - outlineWidth,
1499             min(pixelSnappedBox.maxX() + outlineWidth, (lastline.isEmpty() ? 1000000 : pixelSnappedLastLine.x())),
1500             pixelSnappedBox.y(),
1501             BSTop, outlineColor, outlineStyle,
1502             outlineWidth,
1503             (!lastline.isEmpty() && paintOffset.x() + lastline.x() + 1 < pixelSnappedBox.maxX() + outlineWidth) ? -outlineWidth : outlineWidth,
1504             antialias);
1505 
1506     if (lastline.maxX() < thisline.maxX())
1507         drawLineForBoxSide(graphicsContext,
1508             max(lastline.isEmpty() ? -1000000 : pixelSnappedLastLine.maxX(), pixelSnappedBox.x() - outlineWidth),
1509             pixelSnappedBox.y() - outlineWidth,
1510             pixelSnappedBox.maxX() + outlineWidth,
1511             pixelSnappedBox.y(),
1512             BSTop, outlineColor, outlineStyle,
1513             (!lastline.isEmpty() && pixelSnappedBox.x() - outlineWidth < paintOffset.x() + lastline.maxX()) ? -outlineWidth : outlineWidth,
1514             outlineWidth, antialias);
1515 
1516     if (thisline.x() == thisline.maxX())
1517           drawLineForBoxSide(graphicsContext,
1518             pixelSnappedBox.x() - outlineWidth,
1519             pixelSnappedBox.y() - outlineWidth,
1520             pixelSnappedBox.maxX() + outlineWidth,
1521             pixelSnappedBox.y(),
1522             BSTop, outlineColor, outlineStyle,
1523             outlineWidth,
1524             outlineWidth,
1525             antialias);
1526 
1527     // lower edge
1528     if (thisline.x() < nextline.x())
1529         drawLineForBoxSide(graphicsContext,
1530             pixelSnappedBox.x() - outlineWidth,
1531             pixelSnappedBox.maxY(),
1532             min(pixelSnappedBox.maxX() + outlineWidth, !nextline.isEmpty() ? pixelSnappedNextLine.x() + 1 : 1000000),
1533             pixelSnappedBox.maxY() + outlineWidth,
1534             BSBottom, outlineColor, outlineStyle,
1535             outlineWidth,
1536             (!nextline.isEmpty() && paintOffset.x() + nextline.x() + 1 < pixelSnappedBox.maxX() + outlineWidth) ? -outlineWidth : outlineWidth,
1537             antialias);
1538 
1539     if (nextline.maxX() < thisline.maxX())
1540         drawLineForBoxSide(graphicsContext,
1541             max(!nextline.isEmpty() ? pixelSnappedNextLine.maxX() : -1000000, pixelSnappedBox.x() - outlineWidth),
1542             pixelSnappedBox.maxY(),
1543             pixelSnappedBox.maxX() + outlineWidth,
1544             pixelSnappedBox.maxY() + outlineWidth,
1545             BSBottom, outlineColor, outlineStyle,
1546             (!nextline.isEmpty() && pixelSnappedBox.x() - outlineWidth < paintOffset.x() + nextline.maxX()) ? -outlineWidth : outlineWidth,
1547             outlineWidth, antialias);
1548 
1549     if (thisline.x() == thisline.maxX())
1550           drawLineForBoxSide(graphicsContext,
1551             pixelSnappedBox.x() - outlineWidth,
1552             pixelSnappedBox.maxY(),
1553             pixelSnappedBox.maxX() + outlineWidth,
1554             pixelSnappedBox.maxY() + outlineWidth,
1555             BSBottom, outlineColor, outlineStyle,
1556             outlineWidth,
1557             outlineWidth,
1558             antialias);
1559 }
1560 
addAnnotatedRegions(Vector<AnnotatedRegionValue> & regions)1561 void RenderInline::addAnnotatedRegions(Vector<AnnotatedRegionValue>& regions)
1562 {
1563     // Convert the style regions to absolute coordinates.
1564     if (style()->visibility() != VISIBLE)
1565         return;
1566 
1567     if (style()->getDraggableRegionMode() == DraggableRegionNone)
1568         return;
1569 
1570     AnnotatedRegionValue region;
1571     region.draggable = style()->getDraggableRegionMode() == DraggableRegionDrag;
1572     region.bounds = linesBoundingBox();
1573 
1574     RenderObject* container = containingBlock();
1575     if (!container)
1576         container = this;
1577 
1578     FloatPoint absPos = container->localToAbsolute();
1579     region.bounds.setX(absPos.x() + region.bounds.x());
1580     region.bounds.setY(absPos.y() + region.bounds.y());
1581 
1582     regions.append(region);
1583 }
1584 
1585 } // namespace WebCore
1586