• 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 "RenderInline.h"
25 
26 #include "Chrome.h"
27 #include "FloatQuad.h"
28 #include "GraphicsContext.h"
29 #include "HitTestResult.h"
30 #include "InlineTextBox.h"
31 #include "Page.h"
32 #include "RenderArena.h"
33 #include "RenderBlock.h"
34 #include "RenderLayer.h"
35 #include "RenderTheme.h"
36 #include "RenderView.h"
37 #include "TransformState.h"
38 #include "VisiblePosition.h"
39 
40 #if ENABLE(DASHBOARD_SUPPORT)
41 #include "Frame.h"
42 #endif
43 
44 using namespace std;
45 
46 namespace WebCore {
47 
RenderInline(Node * node)48 RenderInline::RenderInline(Node* node)
49     : RenderBoxModelObject(node)
50     , m_lineHeight(-1)
51     , m_alwaysCreateLineBoxes(false)
52 {
53     setChildrenInline(true);
54 }
55 
destroy()56 void RenderInline::destroy()
57 {
58 #ifndef NDEBUG
59     // Make sure we do not retain "this" in the continuation outline table map of our containing blocks.
60     if (parent() && style()->visibility() == VISIBLE && hasOutline()) {
61         bool containingBlockPaintsContinuationOutline = continuation() || isInlineElementContinuation();
62         if (containingBlockPaintsContinuationOutline) {
63             if (RenderBlock* cb = containingBlock()) {
64                 if (RenderBlock* cbCb = cb->containingBlock())
65                     ASSERT(!cbCb->paintsContinuationOutline(this));
66             }
67         }
68     }
69 #endif
70 
71     // Make sure to destroy anonymous children first while they are still connected to the rest of the tree, so that they will
72     // properly dirty line boxes that they are removed from.  Effects that do :before/:after only on hover could crash otherwise.
73     children()->destroyLeftoverChildren();
74 
75     // Destroy our continuation before anything other than anonymous children.
76     // The reason we don't destroy it before anonymous children is that they may
77     // have continuations of their own that are anonymous children of our continuation.
78     RenderBoxModelObject* continuation = this->continuation();
79     if (continuation) {
80         continuation->destroy();
81         setContinuation(0);
82     }
83 
84     if (!documentBeingDestroyed()) {
85         if (firstLineBox()) {
86             // We can't wait for RenderBoxModelObject::destroy to clear the selection,
87             // because by then we will have nuked the line boxes.
88             // FIXME: The SelectionController should be responsible for this when it
89             // is notified of DOM mutations.
90             if (isSelectionBorder())
91                 view()->clearSelection();
92 
93             // If line boxes are contained inside a root, that means we're an inline.
94             // In that case, we need to remove all the line boxes so that the parent
95             // lines aren't pointing to deleted children. If the first line box does
96             // not have a parent that means they are either already disconnected or
97             // root lines that can just be destroyed without disconnecting.
98             if (firstLineBox()->parent()) {
99                 for (InlineFlowBox* box = firstLineBox(); box; box = box->nextLineBox())
100                     box->remove();
101             }
102         } else if (isInline() && parent())
103             parent()->dirtyLinesFromChangedChild(this);
104     }
105 
106     m_lineBoxes.deleteLineBoxes(renderArena());
107 
108     RenderBoxModelObject::destroy();
109 }
110 
inlineElementContinuation() const111 RenderInline* RenderInline::inlineElementContinuation() const
112 {
113     RenderBoxModelObject* continuation = this->continuation();
114     if (!continuation || continuation->isInline())
115         return toRenderInline(continuation);
116     return toRenderBlock(continuation)->inlineElementContinuation();
117 }
118 
updateBoxModelInfoFromStyle()119 void RenderInline::updateBoxModelInfoFromStyle()
120 {
121     RenderBoxModelObject::updateBoxModelInfoFromStyle();
122 
123     setInline(true); // Needed for run-ins, since run-in is considered a block display type.
124 
125     // FIXME: Support transforms and reflections on inline flows someday.
126     setHasTransform(false);
127     setHasReflection(false);
128 }
129 
styleDidChange(StyleDifference diff,const RenderStyle * oldStyle)130 void RenderInline::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
131 {
132     RenderBoxModelObject::styleDidChange(diff, oldStyle);
133 
134     // Ensure that all of the split inlines pick up the new style. We
135     // only do this if we're an inline, since we don't want to propagate
136     // a block's style to the other inlines.
137     // e.g., <font>foo <h4>goo</h4> moo</font>.  The <font> inlines before
138     // and after the block share the same style, but the block doesn't
139     // need to pass its style on to anyone else.
140     for (RenderInline* currCont = inlineElementContinuation(); currCont; currCont = currCont->inlineElementContinuation()) {
141         RenderBoxModelObject* nextCont = currCont->continuation();
142         currCont->setContinuation(0);
143         currCont->setStyle(style());
144         currCont->setContinuation(nextCont);
145     }
146 
147     m_lineHeight = -1;
148 
149     if (!m_alwaysCreateLineBoxes) {
150         bool alwaysCreateLineBoxes = hasSelfPaintingLayer() || hasBoxDecorations() || style()->hasPadding() || style()->hasMargin() || style()->hasOutline();
151         if (oldStyle && alwaysCreateLineBoxes) {
152             dirtyLineBoxes(false);
153             setNeedsLayout(true);
154         }
155         m_alwaysCreateLineBoxes = alwaysCreateLineBoxes;
156     }
157 
158     // Update pseudos for :before and :after now.
159     if (!isAnonymous() && document()->usesBeforeAfterRules()) {
160         children()->updateBeforeAfterContent(this, BEFORE);
161         children()->updateBeforeAfterContent(this, AFTER);
162     }
163 }
164 
updateAlwaysCreateLineBoxes()165 void RenderInline::updateAlwaysCreateLineBoxes()
166 {
167     // Once we have been tainted once, just assume it will happen again. This way effects like hover highlighting that change the
168     // background color will only cause a layout on the first rollover.
169     if (m_alwaysCreateLineBoxes)
170         return;
171 
172     RenderStyle* parentStyle = parent()->style();
173     RenderInline* parentRenderInline = parent()->isRenderInline() ? toRenderInline(parent()) : 0;
174     bool checkFonts = document()->inNoQuirksMode();
175     bool alwaysCreateLineBoxes = (parentRenderInline && parentRenderInline->alwaysCreateLineBoxes())
176         || (parentRenderInline && parentStyle->verticalAlign() != BASELINE)
177         || style()->verticalAlign() != BASELINE
178         || style()->textEmphasisMark() != TextEmphasisMarkNone
179         || (checkFonts && (!parentStyle->font().fontMetrics().hasIdenticalAscentDescentAndLineGap(style()->font().fontMetrics())
180         || parentStyle->lineHeight() != style()->lineHeight()));
181 
182     if (!alwaysCreateLineBoxes && checkFonts && document()->usesFirstLineRules()) {
183         // Have to check the first line style as well.
184         parentStyle = parent()->style(true);
185         RenderStyle* childStyle = style(true);
186         alwaysCreateLineBoxes = !parentStyle->font().fontMetrics().hasIdenticalAscentDescentAndLineGap(childStyle->font().fontMetrics())
187         || childStyle->verticalAlign() != BASELINE
188         || parentStyle->lineHeight() != childStyle->lineHeight();
189     }
190 
191     if (alwaysCreateLineBoxes) {
192         dirtyLineBoxes(false);
193         m_alwaysCreateLineBoxes = true;
194     }
195 }
196 
addChild(RenderObject * newChild,RenderObject * beforeChild)197 void RenderInline::addChild(RenderObject* newChild, RenderObject* beforeChild)
198 {
199     if (continuation())
200         return addChildToContinuation(newChild, beforeChild);
201     return addChildIgnoringContinuation(newChild, beforeChild);
202 }
203 
nextContinuation(RenderObject * renderer)204 static RenderBoxModelObject* nextContinuation(RenderObject* renderer)
205 {
206     if (renderer->isInline() && !renderer->isReplaced())
207         return toRenderInline(renderer)->continuation();
208     return toRenderBlock(renderer)->inlineElementContinuation();
209 }
210 
continuationBefore(RenderObject * beforeChild)211 RenderBoxModelObject* RenderInline::continuationBefore(RenderObject* beforeChild)
212 {
213     if (beforeChild && beforeChild->parent() == this)
214         return this;
215 
216     RenderBoxModelObject* curr = nextContinuation(this);
217     RenderBoxModelObject* nextToLast = this;
218     RenderBoxModelObject* last = this;
219     while (curr) {
220         if (beforeChild && beforeChild->parent() == curr) {
221             if (curr->firstChild() == beforeChild)
222                 return last;
223             return curr;
224         }
225 
226         nextToLast = last;
227         last = curr;
228         curr = nextContinuation(curr);
229     }
230 
231     if (!beforeChild && !last->firstChild())
232         return nextToLast;
233     return last;
234 }
235 
addChildIgnoringContinuation(RenderObject * newChild,RenderObject * beforeChild)236 void RenderInline::addChildIgnoringContinuation(RenderObject* newChild, RenderObject* beforeChild)
237 {
238     // Make sure we don't append things after :after-generated content if we have it.
239     if (!beforeChild && isAfterContent(lastChild()))
240         beforeChild = lastChild();
241 
242     if (!newChild->isInline() && !newChild->isFloatingOrPositioned()) {
243         // We are placing a block inside an inline. We have to perform a split of this
244         // inline into continuations.  This involves creating an anonymous block box to hold
245         // |newChild|.  We then make that block box a continuation of this inline.  We take all of
246         // the children after |beforeChild| and put them in a clone of this object.
247         RefPtr<RenderStyle> newStyle = RenderStyle::createAnonymousStyle(style());
248         newStyle->setDisplay(BLOCK);
249 
250         RenderBlock* newBox = new (renderArena()) RenderBlock(document() /* anonymous box */);
251         newBox->setStyle(newStyle.release());
252         RenderBoxModelObject* oldContinuation = continuation();
253         setContinuation(newBox);
254 
255         // Someone may have put a <p> inside a <q>, causing a split.  When this happens, the :after content
256         // has to move into the inline continuation.  Call updateBeforeAfterContent to ensure that our :after
257         // content gets properly destroyed.
258         bool isLastChild = (beforeChild == lastChild());
259         if (document()->usesBeforeAfterRules())
260             children()->updateBeforeAfterContent(this, AFTER);
261         if (isLastChild && beforeChild != lastChild())
262             beforeChild = 0; // We destroyed the last child, so now we need to update our insertion
263                              // point to be 0.  It's just a straight append now.
264 
265         splitFlow(beforeChild, newBox, newChild, oldContinuation);
266         return;
267     }
268 
269     RenderBoxModelObject::addChild(newChild, beforeChild);
270 
271     newChild->setNeedsLayoutAndPrefWidthsRecalc();
272 }
273 
cloneInline(RenderInline * src)274 RenderInline* RenderInline::cloneInline(RenderInline* src)
275 {
276     RenderInline* o = new (src->renderArena()) RenderInline(src->node());
277     o->setStyle(src->style());
278     return o;
279 }
280 
splitInlines(RenderBlock * fromBlock,RenderBlock * toBlock,RenderBlock * middleBlock,RenderObject * beforeChild,RenderBoxModelObject * oldCont)281 void RenderInline::splitInlines(RenderBlock* fromBlock, RenderBlock* toBlock,
282                                 RenderBlock* middleBlock,
283                                 RenderObject* beforeChild, RenderBoxModelObject* oldCont)
284 {
285     // Create a clone of this inline.
286     RenderInline* clone = cloneInline(this);
287     clone->setContinuation(oldCont);
288 
289     // Now take all of the children from beforeChild to the end and remove
290     // them from |this| and place them in the clone.
291     RenderObject* o = beforeChild;
292     while (o) {
293         RenderObject* tmp = o;
294         o = tmp->nextSibling();
295         clone->addChildIgnoringContinuation(children()->removeChildNode(this, tmp), 0);
296         tmp->setNeedsLayoutAndPrefWidthsRecalc();
297     }
298 
299     // Hook |clone| up as the continuation of the middle block.
300     middleBlock->setContinuation(clone);
301 
302     // We have been reparented and are now under the fromBlock.  We need
303     // to walk up our inline parent chain until we hit the containing block.
304     // Once we hit the containing block we're done.
305     RenderBoxModelObject* curr = toRenderBoxModelObject(parent());
306     RenderBoxModelObject* currChild = this;
307 
308     // FIXME: Because splitting is O(n^2) as tags nest pathologically, we cap the depth at which we're willing to clone.
309     // There will eventually be a better approach to this problem that will let us nest to a much
310     // greater depth (see bugzilla bug 13430) but for now we have a limit.  This *will* result in
311     // incorrect rendering, but the alternative is to hang forever.
312     unsigned splitDepth = 1;
313     const unsigned cMaxSplitDepth = 200;
314     while (curr && curr != fromBlock) {
315         ASSERT(curr->isRenderInline());
316         if (splitDepth < cMaxSplitDepth) {
317             // Create a new clone.
318             RenderInline* cloneChild = clone;
319             clone = cloneInline(toRenderInline(curr));
320 
321             // Insert our child clone as the first child.
322             clone->addChildIgnoringContinuation(cloneChild, 0);
323 
324             // Hook the clone up as a continuation of |curr|.
325             RenderInline* inlineCurr = toRenderInline(curr);
326             oldCont = inlineCurr->continuation();
327             inlineCurr->setContinuation(clone);
328             clone->setContinuation(oldCont);
329 
330             // Someone may have indirectly caused a <q> to split.  When this happens, the :after content
331             // has to move into the inline continuation.  Call updateBeforeAfterContent to ensure that the inline's :after
332             // content gets properly destroyed.
333             if (document()->usesBeforeAfterRules())
334                 inlineCurr->children()->updateBeforeAfterContent(inlineCurr, AFTER);
335 
336             // Now we need to take all of the children starting from the first child
337             // *after* currChild and append them all to the clone.
338             o = currChild->nextSibling();
339             while (o) {
340                 RenderObject* tmp = o;
341                 o = tmp->nextSibling();
342                 clone->addChildIgnoringContinuation(inlineCurr->children()->removeChildNode(curr, tmp), 0);
343                 tmp->setNeedsLayoutAndPrefWidthsRecalc();
344             }
345         }
346 
347         // Keep walking up the chain.
348         currChild = curr;
349         curr = toRenderBoxModelObject(curr->parent());
350         splitDepth++;
351     }
352 
353     // Now we are at the block level. We need to put the clone into the toBlock.
354     toBlock->children()->appendChildNode(toBlock, clone);
355 
356     // Now take all the children after currChild and remove them from the fromBlock
357     // and put them in the toBlock.
358     o = currChild->nextSibling();
359     while (o) {
360         RenderObject* tmp = o;
361         o = tmp->nextSibling();
362         toBlock->children()->appendChildNode(toBlock, fromBlock->children()->removeChildNode(fromBlock, tmp));
363     }
364 }
365 
splitFlow(RenderObject * beforeChild,RenderBlock * newBlockBox,RenderObject * newChild,RenderBoxModelObject * oldCont)366 void RenderInline::splitFlow(RenderObject* beforeChild, RenderBlock* newBlockBox,
367                              RenderObject* newChild, RenderBoxModelObject* oldCont)
368 {
369     RenderBlock* pre = 0;
370     RenderBlock* block = containingBlock();
371 
372     // Delete our line boxes before we do the inline split into continuations.
373     block->deleteLineBoxTree();
374 
375     bool madeNewBeforeBlock = false;
376     if (block->isAnonymousBlock() && (!block->parent() || !block->parent()->createsAnonymousWrapper())) {
377         // We can reuse this block and make it the preBlock of the next continuation.
378         pre = block;
379         pre->removePositionedObjects(0);
380         block = block->containingBlock();
381     } else {
382         // No anonymous block available for use.  Make one.
383         pre = block->createAnonymousBlock();
384         madeNewBeforeBlock = true;
385     }
386 
387     RenderBlock* post = block->createAnonymousBlock();
388 
389     RenderObject* boxFirst = madeNewBeforeBlock ? block->firstChild() : pre->nextSibling();
390     if (madeNewBeforeBlock)
391         block->children()->insertChildNode(block, pre, boxFirst);
392     block->children()->insertChildNode(block, newBlockBox, boxFirst);
393     block->children()->insertChildNode(block, post, boxFirst);
394     block->setChildrenInline(false);
395 
396     if (madeNewBeforeBlock) {
397         RenderObject* o = boxFirst;
398         while (o) {
399             RenderObject* no = o;
400             o = no->nextSibling();
401             pre->children()->appendChildNode(pre, block->children()->removeChildNode(block, no));
402             no->setNeedsLayoutAndPrefWidthsRecalc();
403         }
404     }
405 
406     splitInlines(pre, post, newBlockBox, beforeChild, oldCont);
407 
408     // We already know the newBlockBox isn't going to contain inline kids, so avoid wasting
409     // time in makeChildrenNonInline by just setting this explicitly up front.
410     newBlockBox->setChildrenInline(false);
411 
412     // We delayed adding the newChild until now so that the |newBlockBox| would be fully
413     // connected, thus allowing newChild access to a renderArena should it need
414     // to wrap itself in additional boxes (e.g., table construction).
415     newBlockBox->addChild(newChild);
416 
417     // Always just do a full layout in order to ensure that line boxes (especially wrappers for images)
418     // get deleted properly.  Because objects moves from the pre block into the post block, we want to
419     // make new line boxes instead of leaving the old line boxes around.
420     pre->setNeedsLayoutAndPrefWidthsRecalc();
421     block->setNeedsLayoutAndPrefWidthsRecalc();
422     post->setNeedsLayoutAndPrefWidthsRecalc();
423 }
424 
addChildToContinuation(RenderObject * newChild,RenderObject * beforeChild)425 void RenderInline::addChildToContinuation(RenderObject* newChild, RenderObject* beforeChild)
426 {
427     RenderBoxModelObject* flow = continuationBefore(beforeChild);
428     ASSERT(!beforeChild || beforeChild->parent()->isRenderBlock() || beforeChild->parent()->isRenderInline());
429     RenderBoxModelObject* beforeChildParent = 0;
430     if (beforeChild)
431         beforeChildParent = toRenderBoxModelObject(beforeChild->parent());
432     else {
433         RenderBoxModelObject* cont = nextContinuation(flow);
434         if (cont)
435             beforeChildParent = cont;
436         else
437             beforeChildParent = flow;
438     }
439 
440     if (newChild->isFloatingOrPositioned())
441         return beforeChildParent->addChildIgnoringContinuation(newChild, beforeChild);
442 
443     // A continuation always consists of two potential candidates: an inline or an anonymous
444     // block box holding block children.
445     bool childInline = newChild->isInline();
446     bool bcpInline = beforeChildParent->isInline();
447     bool flowInline = flow->isInline();
448 
449     if (flow == beforeChildParent)
450         return flow->addChildIgnoringContinuation(newChild, beforeChild);
451     else {
452         // The goal here is to match up if we can, so that we can coalesce and create the
453         // minimal # of continuations needed for the inline.
454         if (childInline == bcpInline)
455             return beforeChildParent->addChildIgnoringContinuation(newChild, beforeChild);
456         else if (flowInline == childInline)
457             return flow->addChildIgnoringContinuation(newChild, 0); // Just treat like an append.
458         else
459             return beforeChildParent->addChildIgnoringContinuation(newChild, beforeChild);
460     }
461 }
462 
paint(PaintInfo & paintInfo,int tx,int ty)463 void RenderInline::paint(PaintInfo& paintInfo, int tx, int ty)
464 {
465     m_lineBoxes.paint(this, paintInfo, tx, ty);
466 }
467 
absoluteRects(Vector<IntRect> & rects,int tx,int ty)468 void RenderInline::absoluteRects(Vector<IntRect>& rects, int tx, int ty)
469 {
470     if (!alwaysCreateLineBoxes())
471         culledInlineAbsoluteRects(this, rects, IntSize(tx, ty));
472     else if (InlineFlowBox* curr = firstLineBox()) {
473         for (; curr; curr = curr->nextLineBox())
474             rects.append(enclosingIntRect(FloatRect(tx + curr->x(), ty + curr->y(), curr->width(), curr->height())));
475     } else
476         rects.append(IntRect(tx, ty, 0, 0));
477 
478     if (continuation()) {
479         if (continuation()->isBox()) {
480             RenderBox* box = toRenderBox(continuation());
481             continuation()->absoluteRects(rects,
482                                           tx - containingBlock()->x() + box->x(),
483                                           ty - containingBlock()->y() + box->y());
484         } else
485             continuation()->absoluteRects(rects, tx - containingBlock()->x(), ty - containingBlock()->y());
486     }
487 }
488 
culledInlineAbsoluteRects(const RenderInline * container,Vector<IntRect> & rects,const IntSize & offset)489 void RenderInline::culledInlineAbsoluteRects(const RenderInline* container, Vector<IntRect>& rects, const IntSize& offset)
490 {
491     bool isHorizontal = style()->isHorizontalWritingMode();
492     for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) {
493         if (curr->isFloatingOrPositioned())
494             continue;
495 
496         // We want to get the margin box in the inline direction, and then use our font ascent/descent in the block
497         // direction (aligned to the root box's baseline).
498         if (curr->isBox()) {
499             RenderBox* currBox = toRenderBox(curr);
500             if (currBox->inlineBoxWrapper()) {
501                 RootInlineBox* rootBox = currBox->inlineBoxWrapper()->root();
502                 int logicalTop = rootBox->logicalTop() + (rootBox->renderer()->style(rootBox->isFirstLineStyle())->font().fontMetrics().ascent() - container->style(rootBox->isFirstLineStyle())->font().fontMetrics().ascent());
503                 int logicalHeight = container->style(rootBox->isFirstLineStyle())->font().fontMetrics().height();
504                 FloatRect result;
505                 if (isHorizontal)
506                     result = FloatRect(offset.width() + currBox->inlineBoxWrapper()->x() - currBox->marginLeft(), offset.height() + logicalTop, currBox->width() + currBox->marginLeft() + currBox->marginRight(), logicalHeight);
507                 else
508                     result = FloatRect(offset.width() + logicalTop, offset.height() + currBox->inlineBoxWrapper()->y() - currBox->marginTop(), logicalHeight, currBox->height() + currBox->marginTop() + currBox->marginBottom());
509                 rects.append(enclosingIntRect(result));
510             }
511         } else if (curr->isRenderInline()) {
512             // If the child doesn't need line boxes either, then we can recur.
513             RenderInline* currInline = toRenderInline(curr);
514             if (!currInline->alwaysCreateLineBoxes())
515                 currInline->culledInlineAbsoluteRects(container, rects, offset);
516             else {
517                 for (InlineFlowBox* childLine = currInline->firstLineBox(); childLine; childLine = childLine->nextLineBox()) {
518                     RootInlineBox* rootBox = childLine->root();
519                     int logicalTop = rootBox->logicalTop() + (rootBox->renderer()->style(rootBox->isFirstLineStyle())->font().fontMetrics().ascent() - container->style(rootBox->isFirstLineStyle())->font().fontMetrics().ascent());
520                     int logicalHeight = container->style(rootBox->isFirstLineStyle())->font().fontMetrics().height();
521                     FloatRect result;
522                     if (isHorizontal)
523                         result = FloatRect(offset.width() + childLine->x() - childLine->marginLogicalLeft(),
524                             offset.height() + logicalTop,
525                             childLine->logicalWidth() + childLine->marginLogicalLeft() + childLine->marginLogicalRight(),
526                             logicalHeight);
527                     else
528                         result = FloatRect(offset.width() + logicalTop,
529                             offset.height() + childLine->y() - childLine->marginLogicalLeft(),
530                             logicalHeight,
531                             childLine->logicalWidth() + childLine->marginLogicalLeft() + childLine->marginLogicalRight());
532                     rects.append(enclosingIntRect(result));
533                 }
534             }
535         } else if (curr->isText()) {
536             RenderText* currText = toRenderText(curr);
537             for (InlineTextBox* childText = currText->firstTextBox(); childText; childText = childText->nextTextBox()) {
538                 RootInlineBox* rootBox = childText->root();
539                 int logicalTop = rootBox->logicalTop() + (rootBox->renderer()->style(rootBox->isFirstLineStyle())->font().fontMetrics().ascent() - container->style(rootBox->isFirstLineStyle())->font().fontMetrics().ascent());
540                 int logicalHeight = container->style(rootBox->isFirstLineStyle())->font().fontMetrics().height();
541                 FloatRect result;
542                 if (isHorizontal)
543                     result = FloatRect(offset.width() + childText->x(), offset.height() + logicalTop, childText->logicalWidth(), logicalHeight);
544                 else
545                     result = FloatRect(offset.width() + logicalTop, offset.height() + childText->y(), logicalHeight, childText->logicalWidth());
546                 rects.append(enclosingIntRect(result));
547             }
548         }
549     }
550 }
551 
absoluteQuads(Vector<FloatQuad> & quads)552 void RenderInline::absoluteQuads(Vector<FloatQuad>& quads)
553 {
554     if (!alwaysCreateLineBoxes())
555         culledInlineAbsoluteQuads(this, quads);
556     else if (InlineFlowBox* curr = firstLineBox()) {
557         for (; curr; curr = curr->nextLineBox()) {
558             FloatRect localRect(curr->x(), curr->y(), curr->width(), curr->height());
559             quads.append(localToAbsoluteQuad(localRect));
560         }
561     } else
562         quads.append(localToAbsoluteQuad(FloatRect()));
563 
564     if (continuation())
565         continuation()->absoluteQuads(quads);
566 }
567 
culledInlineAbsoluteQuads(const RenderInline * container,Vector<FloatQuad> & quads)568 void RenderInline::culledInlineAbsoluteQuads(const RenderInline* container, Vector<FloatQuad>& quads)
569 {
570     if (!culledInlineFirstLineBox()) {
571         quads.append(localToAbsoluteQuad(FloatRect()));
572         return;
573     }
574 
575     bool isHorizontal = style()->isHorizontalWritingMode();
576     for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) {
577         if (curr->isFloatingOrPositioned())
578             continue;
579 
580         // We want to get the margin box in the inline direction, and then use our font ascent/descent in the block
581         // direction (aligned to the root box's baseline).
582         if (curr->isBox()) {
583             RenderBox* currBox = toRenderBox(curr);
584             if (currBox->inlineBoxWrapper()) {
585                 RootInlineBox* rootBox = currBox->inlineBoxWrapper()->root();
586                 int logicalTop = rootBox->logicalTop() + (rootBox->renderer()->style(rootBox->isFirstLineStyle())->font().fontMetrics().ascent() - container->style(rootBox->isFirstLineStyle())->font().fontMetrics().ascent());
587                 int logicalHeight = container->style(rootBox->isFirstLineStyle())->font().fontMetrics().height();
588                 FloatRect result;
589                 if (isHorizontal)
590                     result = FloatRect(currBox->inlineBoxWrapper()->x() - currBox->marginLeft(), logicalTop, currBox->width() + currBox->marginLeft() + currBox->marginRight(), logicalHeight);
591                 else
592                     result = FloatRect(logicalTop, currBox->inlineBoxWrapper()->y() - currBox->marginTop(), logicalHeight, currBox->height() + currBox->marginTop() + currBox->marginBottom());
593                 quads.append(localToAbsoluteQuad(result));
594             }
595         } else if (curr->isRenderInline()) {
596             // If the child doesn't need line boxes either, then we can recur.
597             RenderInline* currInline = toRenderInline(curr);
598             if (!currInline->alwaysCreateLineBoxes())
599                 currInline->culledInlineAbsoluteQuads(container, quads);
600             else {
601                 for (InlineFlowBox* childLine = currInline->firstLineBox(); childLine; childLine = childLine->nextLineBox()) {
602                     RootInlineBox* rootBox = childLine->root();
603                     int logicalTop = rootBox->logicalTop() + (rootBox->renderer()->style(rootBox->isFirstLineStyle())->font().fontMetrics().ascent() - container->style(rootBox->isFirstLineStyle())->font().fontMetrics().ascent());
604                     int logicalHeight = container->style(rootBox->isFirstLineStyle())->font().fontMetrics().height();
605                     FloatRect result;
606                     if (isHorizontal)
607                         result = FloatRect(childLine->x() - childLine->marginLogicalLeft(),
608                             logicalTop,
609                             childLine->logicalWidth() + childLine->marginLogicalLeft() + childLine->marginLogicalRight(),
610                             logicalHeight);
611                     else
612                         result = FloatRect(logicalTop,
613                             childLine->y() - childLine->marginLogicalLeft(),
614                             logicalHeight,
615                             childLine->logicalWidth() + childLine->marginLogicalLeft() + childLine->marginLogicalRight());
616                     quads.append(localToAbsoluteQuad(result));
617                 }
618             }
619         } else if (curr->isText()) {
620             RenderText* currText = toRenderText(curr);
621             for (InlineTextBox* childText = currText->firstTextBox(); childText; childText = childText->nextTextBox()) {
622                 RootInlineBox* rootBox = childText->root();
623                 int logicalTop = rootBox->logicalTop() + (rootBox->renderer()->style(rootBox->isFirstLineStyle())->font().fontMetrics().ascent() - container->style(rootBox->isFirstLineStyle())->font().fontMetrics().ascent());
624                 int logicalHeight = container->style(rootBox->isFirstLineStyle())->font().fontMetrics().height();
625                 FloatRect result;
626                 if (isHorizontal)
627                     result = FloatRect(childText->x(), logicalTop, childText->logicalWidth(), logicalHeight);
628                 else
629                     result = FloatRect(logicalTop, childText->y(), logicalHeight, childText->logicalWidth());
630                 quads.append(localToAbsoluteQuad(result));
631             }
632         }
633     }
634 }
635 
offsetLeft() const636 int RenderInline::offsetLeft() const
637 {
638     int x = RenderBoxModelObject::offsetLeft();
639     if (InlineBox* firstBox = firstLineBoxIncludingCulling())
640         x += firstBox->x();
641     return x;
642 }
643 
offsetTop() const644 int RenderInline::offsetTop() const
645 {
646     int y = RenderBoxModelObject::offsetTop();
647     if (InlineBox* firstBox = firstLineBoxIncludingCulling())
648         y += firstBox->y();
649     return y;
650 }
651 
computeMargin(const RenderInline * renderer,const Length & margin)652 static int computeMargin(const RenderInline* renderer, const Length& margin)
653 {
654     if (margin.isAuto())
655         return 0;
656     if (margin.isFixed())
657         return margin.value();
658     if (margin.isPercent())
659         return margin.calcMinValue(max(0, renderer->containingBlock()->availableLogicalWidth()));
660     return 0;
661 }
662 
marginLeft() const663 int RenderInline::marginLeft() const
664 {
665     return computeMargin(this, style()->marginLeft());
666 }
667 
marginRight() const668 int RenderInline::marginRight() const
669 {
670     return computeMargin(this, style()->marginRight());
671 }
672 
marginTop() const673 int RenderInline::marginTop() const
674 {
675     return computeMargin(this, style()->marginTop());
676 }
677 
marginBottom() const678 int RenderInline::marginBottom() const
679 {
680     return computeMargin(this, style()->marginBottom());
681 }
682 
marginStart() const683 int RenderInline::marginStart() const
684 {
685     return computeMargin(this, style()->marginStart());
686 }
687 
marginEnd() const688 int RenderInline::marginEnd() const
689 {
690     return computeMargin(this, style()->marginEnd());
691 }
692 
marginBefore() const693 int RenderInline::marginBefore() const
694 {
695     return computeMargin(this, style()->marginBefore());
696 }
697 
marginAfter() const698 int RenderInline::marginAfter() const
699 {
700     return computeMargin(this, style()->marginAfter());
701 }
702 
renderName() const703 const char* RenderInline::renderName() const
704 {
705     if (isRelPositioned())
706         return "RenderInline (relative positioned)";
707     if (isAnonymous())
708         return "RenderInline (generated)";
709     if (isRunIn())
710         return "RenderInline (run-in)";
711     return "RenderInline";
712 }
713 
nodeAtPoint(const HitTestRequest & request,HitTestResult & result,int x,int y,int tx,int ty,HitTestAction hitTestAction)714 bool RenderInline::nodeAtPoint(const HitTestRequest& request, HitTestResult& result,
715                                 int x, int y, int tx, int ty, HitTestAction hitTestAction)
716 {
717     return m_lineBoxes.hitTest(this, request, result, x, y, tx, ty, hitTestAction);
718 }
719 
positionForPoint(const IntPoint & point)720 VisiblePosition RenderInline::positionForPoint(const IntPoint& point)
721 {
722     // FIXME: Does not deal with relative positioned inlines (should it?)
723     RenderBlock* cb = containingBlock();
724     if (firstLineBox()) {
725         // This inline actually has a line box.  We must have clicked in the border/padding of one of these boxes.  We
726         // should try to find a result by asking our containing block.
727         return cb->positionForPoint(point);
728     }
729 
730     // Translate the coords from the pre-anonymous block to the post-anonymous block.
731     int parentBlockX = cb->x() + point.x();
732     int parentBlockY = cb->y() + point.y();
733     RenderBoxModelObject* c = continuation();
734     while (c) {
735         RenderBox* contBlock = c->isInline() ? c->containingBlock() : toRenderBlock(c);
736         if (c->isInline() || c->firstChild())
737             return c->positionForCoordinates(parentBlockX - contBlock->x(), parentBlockY - contBlock->y());
738         c = toRenderBlock(c)->inlineElementContinuation();
739     }
740 
741     return RenderBoxModelObject::positionForPoint(point);
742 }
743 
linesBoundingBox() const744 IntRect RenderInline::linesBoundingBox() const
745 {
746     if (!alwaysCreateLineBoxes()) {
747         ASSERT(!firstLineBox());
748         return enclosingIntRect(culledInlineBoundingBox(this));
749     }
750 
751     IntRect result;
752 
753     // 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
754     // 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
755     // builds and help us someday figure out why.  We also put in a redundant check of lastLineBox() to avoid the crash for now.
756     ASSERT(!firstLineBox() == !lastLineBox());  // Either both are null or both exist.
757     if (firstLineBox() && lastLineBox()) {
758         // Return the width of the minimal left side and the maximal right side.
759         float logicalLeftSide = 0;
760         float logicalRightSide = 0;
761         for (InlineFlowBox* curr = firstLineBox(); curr; curr = curr->nextLineBox()) {
762             if (curr == firstLineBox() || curr->logicalLeft() < logicalLeftSide)
763                 logicalLeftSide = curr->logicalLeft();
764             if (curr == firstLineBox() || curr->logicalRight() > logicalRightSide)
765                 logicalRightSide = curr->logicalRight();
766         }
767 
768         bool isHorizontal = style()->isHorizontalWritingMode();
769 
770         float x = isHorizontal ? logicalLeftSide : firstLineBox()->x();
771         float y = isHorizontal ? firstLineBox()->y() : logicalLeftSide;
772         float width = isHorizontal ? logicalRightSide - logicalLeftSide : lastLineBox()->logicalBottom() - x;
773         float height = isHorizontal ? lastLineBox()->logicalBottom() - y : logicalRightSide - logicalLeftSide;
774         result = enclosingIntRect(FloatRect(x, y, width, height));
775     }
776 
777     return result;
778 }
779 
culledInlineBoundingBox(const RenderInline * container) const780 FloatRect RenderInline::culledInlineBoundingBox(const RenderInline* container) const
781 {
782     FloatRect result;
783     bool isHorizontal = style()->isHorizontalWritingMode();
784     for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) {
785         if (curr->isFloatingOrPositioned())
786             continue;
787 
788         // We want to get the margin box in the inline direction, and then use our font ascent/descent in the block
789         // direction (aligned to the root box's baseline).
790         if (curr->isBox()) {
791             RenderBox* currBox = toRenderBox(curr);
792             if (currBox->inlineBoxWrapper()) {
793                 RootInlineBox* rootBox = currBox->inlineBoxWrapper()->root();
794                 int logicalTop = rootBox->logicalTop() + (rootBox->renderer()->style(rootBox->isFirstLineStyle())->font().fontMetrics().ascent() - container->style(rootBox->isFirstLineStyle())->font().fontMetrics().ascent());
795                 int logicalHeight = container->style(rootBox->isFirstLineStyle())->font().fontMetrics().height();
796                 if (isHorizontal)
797                     result.uniteIfNonZero(FloatRect(currBox->inlineBoxWrapper()->x() - currBox->marginLeft(), logicalTop, currBox->width() + currBox->marginLeft() + currBox->marginRight(), logicalHeight));
798                 else
799                     result.uniteIfNonZero(FloatRect(logicalTop, currBox->inlineBoxWrapper()->y() - currBox->marginTop(), logicalHeight, currBox->height() + currBox->marginTop() + currBox->marginBottom()));
800             }
801         } else if (curr->isRenderInline()) {
802             // If the child doesn't need line boxes either, then we can recur.
803             RenderInline* currInline = toRenderInline(curr);
804             if (!currInline->alwaysCreateLineBoxes())
805                 result.uniteIfNonZero(currInline->culledInlineBoundingBox(container));
806             else {
807                 for (InlineFlowBox* childLine = currInline->firstLineBox(); childLine; childLine = childLine->nextLineBox()) {
808                     RootInlineBox* rootBox = childLine->root();
809                     int logicalTop = rootBox->logicalTop() + (rootBox->renderer()->style(rootBox->isFirstLineStyle())->font().fontMetrics().ascent() - container->style(rootBox->isFirstLineStyle())->font().fontMetrics().ascent());
810                     int logicalHeight = container->style(rootBox->isFirstLineStyle())->font().fontMetrics().height();
811                     if (isHorizontal)
812                         result.uniteIfNonZero(FloatRect(childLine->x() - childLine->marginLogicalLeft(),
813                             logicalTop,
814                             childLine->logicalWidth() + childLine->marginLogicalLeft() + childLine->marginLogicalRight(),
815                             logicalHeight));
816                     else
817                         result.uniteIfNonZero(FloatRect(logicalTop,
818                             childLine->y() - childLine->marginLogicalLeft(),
819                             logicalHeight,
820                             childLine->logicalWidth() + childLine->marginLogicalLeft() + childLine->marginLogicalRight()));
821 
822                 }
823             }
824         } else if (curr->isText()) {
825             RenderText* currText = toRenderText(curr);
826             for (InlineTextBox* childText = currText->firstTextBox(); childText; childText = childText->nextTextBox()) {
827                 RootInlineBox* rootBox = childText->root();
828                 int logicalTop = rootBox->logicalTop() + (rootBox->renderer()->style(rootBox->isFirstLineStyle())->font().fontMetrics().ascent() - container->style(rootBox->isFirstLineStyle())->font().fontMetrics().ascent());
829                 int logicalHeight = container->style(rootBox->isFirstLineStyle())->font().fontMetrics().height();
830                 if (isHorizontal)
831                     result.uniteIfNonZero(FloatRect(childText->x(), logicalTop, childText->logicalWidth(), logicalHeight));
832                 else
833                     result.uniteIfNonZero(FloatRect(logicalTop, childText->y(), logicalHeight, childText->logicalWidth()));
834             }
835         }
836     }
837     return enclosingIntRect(result);
838 }
839 
culledInlineFirstLineBox() const840 InlineBox* RenderInline::culledInlineFirstLineBox() const
841 {
842     for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) {
843         if (curr->isFloatingOrPositioned())
844             continue;
845 
846         // We want to get the margin box in the inline direction, and then use our font ascent/descent in the block
847         // direction (aligned to the root box's baseline).
848         if (curr->isBox()) {
849             RenderBox* currBox = toRenderBox(curr);
850             if (currBox->inlineBoxWrapper())
851                 return currBox->inlineBoxWrapper();
852         } else if (curr->isRenderInline()) {
853             RenderInline* currInline = toRenderInline(curr);
854             InlineBox* result = currInline->firstLineBoxIncludingCulling();
855             if (result)
856                 return result;
857         } else if (curr->isText()) {
858             RenderText* currText = toRenderText(curr);
859             if (currText->firstTextBox())
860                 return currText->firstTextBox();
861         }
862     }
863     return 0;
864 }
865 
culledInlineLastLineBox() const866 InlineBox* RenderInline::culledInlineLastLineBox() const
867 {
868     for (RenderObject* curr = lastChild(); curr; curr = curr->previousSibling()) {
869         if (curr->isFloatingOrPositioned())
870             continue;
871 
872         // We want to get the margin box in the inline direction, and then use our font ascent/descent in the block
873         // direction (aligned to the root box's baseline).
874         if (curr->isBox()) {
875             RenderBox* currBox = toRenderBox(curr);
876             if (currBox->inlineBoxWrapper())
877                 return currBox->inlineBoxWrapper();
878         } else if (curr->isRenderInline()) {
879             RenderInline* currInline = toRenderInline(curr);
880             InlineBox* result = currInline->lastLineBoxIncludingCulling();
881             if (result)
882                 return result;
883         } else if (curr->isText()) {
884             RenderText* currText = toRenderText(curr);
885             if (currText->lastTextBox())
886                 return currText->lastTextBox();
887         }
888     }
889     return 0;
890 }
891 
culledInlineVisualOverflowBoundingBox() const892 IntRect RenderInline::culledInlineVisualOverflowBoundingBox() const
893 {
894     IntRect result(culledInlineBoundingBox(this));
895     bool isHorizontal = style()->isHorizontalWritingMode();
896     for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) {
897         if (curr->isFloatingOrPositioned())
898             continue;
899 
900         // For overflow we just have to propagate by hand and recompute it all.
901         if (curr->isBox()) {
902             RenderBox* currBox = toRenderBox(curr);
903             if (!currBox->hasSelfPaintingLayer() && currBox->inlineBoxWrapper()) {
904                 IntRect logicalRect = currBox->logicalVisualOverflowRectForPropagation(style());
905                 if (isHorizontal) {
906                     logicalRect.move(currBox->x(), currBox->y());
907                     result.uniteIfNonZero(logicalRect);
908                 } else {
909                     logicalRect.move(currBox->y(), currBox->x());
910                     result.uniteIfNonZero(logicalRect.transposedRect());
911                 }
912             }
913         } else if (curr->isRenderInline()) {
914             // If the child doesn't need line boxes either, then we can recur.
915             RenderInline* currInline = toRenderInline(curr);
916             if (!currInline->alwaysCreateLineBoxes())
917                 result.uniteIfNonZero(currInline->culledInlineVisualOverflowBoundingBox());
918             else if (!currInline->hasSelfPaintingLayer())
919                 result.uniteIfNonZero(currInline->linesVisualOverflowBoundingBox());
920         } else if (curr->isText()) {
921             // FIXME; Overflow from text boxes is lost. We will need to cache this information in
922             // InlineTextBoxes.
923             RenderText* currText = toRenderText(curr);
924             result.uniteIfNonZero(currText->linesVisualOverflowBoundingBox());
925         }
926     }
927     return result;
928 }
929 
linesVisualOverflowBoundingBox() const930 IntRect RenderInline::linesVisualOverflowBoundingBox() const
931 {
932     if (!alwaysCreateLineBoxes())
933         return culledInlineVisualOverflowBoundingBox();
934 
935     if (!firstLineBox() || !lastLineBox())
936         return IntRect();
937 
938     // Return the width of the minimal left side and the maximal right side.
939     int logicalLeftSide = numeric_limits<int>::max();
940     int logicalRightSide = numeric_limits<int>::min();
941     for (InlineFlowBox* curr = firstLineBox(); curr; curr = curr->nextLineBox()) {
942         logicalLeftSide = min(logicalLeftSide, curr->logicalLeftVisualOverflow());
943         logicalRightSide = max(logicalRightSide, curr->logicalRightVisualOverflow());
944     }
945 
946     RootInlineBox* firstRootBox = firstLineBox()->root();
947     RootInlineBox* lastRootBox = lastLineBox()->root();
948 
949     int logicalTop = firstLineBox()->logicalTopVisualOverflow(firstRootBox->lineTop());
950     int logicalWidth = logicalRightSide - logicalLeftSide;
951     int logicalHeight = lastLineBox()->logicalBottomVisualOverflow(lastRootBox->lineBottom()) - logicalTop;
952 
953     IntRect rect(logicalLeftSide, logicalTop, logicalWidth, logicalHeight);
954     if (!style()->isHorizontalWritingMode())
955         rect = rect.transposedRect();
956     return rect;
957 }
958 
clippedOverflowRectForRepaint(RenderBoxModelObject * repaintContainer)959 IntRect RenderInline::clippedOverflowRectForRepaint(RenderBoxModelObject* repaintContainer)
960 {
961     // Only run-ins are allowed in here during layout.
962     ASSERT(!view() || !view()->layoutStateEnabled() || isRunIn());
963 
964     if (!firstLineBoxIncludingCulling() && !continuation())
965         return IntRect();
966 
967     // Find our leftmost position.
968     IntRect boundingBox(linesVisualOverflowBoundingBox());
969     int left = boundingBox.x();
970     int top = boundingBox.y();
971 
972     // Now invalidate a rectangle.
973     int ow = style() ? style()->outlineSize() : 0;
974 
975     // We need to add in the relative position offsets of any inlines (including us) up to our
976     // containing block.
977     RenderBlock* cb = containingBlock();
978     for (RenderObject* inlineFlow = this; inlineFlow && inlineFlow->isRenderInline() && inlineFlow != cb;
979          inlineFlow = inlineFlow->parent()) {
980          if (inlineFlow->style()->position() == RelativePosition && inlineFlow->hasLayer())
981             toRenderInline(inlineFlow)->layer()->relativePositionOffset(left, top);
982     }
983 
984     IntRect r(-ow + left, -ow + top, boundingBox.width() + ow * 2, boundingBox.height() + ow * 2);
985 
986     if (cb->hasColumns())
987         cb->adjustRectForColumns(r);
988 
989     if (cb->hasOverflowClip()) {
990         // cb->height() is inaccurate if we're in the middle of a layout of |cb|, so use the
991         // layer's size instead.  Even if the layer's size is wrong, the layer itself will repaint
992         // anyway if its size does change.
993         IntRect repaintRect(r);
994         repaintRect.move(-cb->layer()->scrolledContentOffset()); // For overflow:auto/scroll/hidden.
995 
996         IntRect boxRect(0, 0, cb->layer()->width(), cb->layer()->height());
997         r = intersection(repaintRect, boxRect);
998     }
999 
1000     // FIXME: need to ensure that we compute the correct repaint rect when the repaint container
1001     // is an inline.
1002     if (repaintContainer != this)
1003         cb->computeRectForRepaint(repaintContainer, r);
1004 
1005     if (ow) {
1006         for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) {
1007             if (!curr->isText()) {
1008                 IntRect childRect = curr->rectWithOutlineForRepaint(repaintContainer, ow);
1009                 r.unite(childRect);
1010             }
1011         }
1012 
1013         if (continuation() && !continuation()->isInline()) {
1014             IntRect contRect = continuation()->rectWithOutlineForRepaint(repaintContainer, ow);
1015             r.unite(contRect);
1016         }
1017     }
1018 
1019     return r;
1020 }
1021 
rectWithOutlineForRepaint(RenderBoxModelObject * repaintContainer,int outlineWidth)1022 IntRect RenderInline::rectWithOutlineForRepaint(RenderBoxModelObject* repaintContainer, int outlineWidth)
1023 {
1024     IntRect r(RenderBoxModelObject::rectWithOutlineForRepaint(repaintContainer, outlineWidth));
1025     for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) {
1026         if (!curr->isText())
1027             r.unite(curr->rectWithOutlineForRepaint(repaintContainer, outlineWidth));
1028     }
1029     return r;
1030 }
1031 
computeRectForRepaint(RenderBoxModelObject * repaintContainer,IntRect & rect,bool fixed)1032 void RenderInline::computeRectForRepaint(RenderBoxModelObject* repaintContainer, IntRect& rect, bool fixed)
1033 {
1034     if (RenderView* v = view()) {
1035         // LayoutState is only valid for root-relative repainting
1036         if (v->layoutStateEnabled() && !repaintContainer) {
1037             LayoutState* layoutState = v->layoutState();
1038             if (style()->position() == RelativePosition && layer())
1039                 rect.move(layer()->relativePositionOffset());
1040             rect.move(layoutState->m_paintOffset);
1041             if (layoutState->m_clipped)
1042                 rect.intersect(layoutState->m_clipRect);
1043             return;
1044         }
1045     }
1046 
1047     if (repaintContainer == this)
1048         return;
1049 
1050     bool containerSkipped;
1051     RenderObject* o = container(repaintContainer, &containerSkipped);
1052     if (!o)
1053         return;
1054 
1055     IntPoint topLeft = rect.location();
1056 
1057     if (o->isBlockFlow() && style()->position() != AbsolutePosition && style()->position() != FixedPosition) {
1058         RenderBlock* cb = toRenderBlock(o);
1059         if (cb->hasColumns()) {
1060             IntRect repaintRect(topLeft, rect.size());
1061             cb->adjustRectForColumns(repaintRect);
1062             topLeft = repaintRect.location();
1063             rect = repaintRect;
1064         }
1065     }
1066 
1067     if (style()->position() == RelativePosition && layer()) {
1068         // Apply the relative position offset when invalidating a rectangle.  The layer
1069         // is translated, but the render box isn't, so we need to do this to get the
1070         // right dirty rect.  Since this is called from RenderObject::setStyle, the relative position
1071         // flag on the RenderObject has been cleared, so use the one on the style().
1072         topLeft += layer()->relativePositionOffset();
1073     }
1074 
1075     // FIXME: We ignore the lightweight clipping rect that controls use, since if |o| is in mid-layout,
1076     // its controlClipRect will be wrong. For overflow clip we use the values cached by the layer.
1077     if (o->hasOverflowClip()) {
1078         RenderBox* containerBox = toRenderBox(o);
1079 
1080         // o->height() is inaccurate if we're in the middle of a layout of |o|, so use the
1081         // layer's size instead.  Even if the layer's size is wrong, the layer itself will repaint
1082         // anyway if its size does change.
1083         topLeft -= containerBox->layer()->scrolledContentOffset(); // For overflow:auto/scroll/hidden.
1084 
1085         IntRect repaintRect(topLeft, rect.size());
1086         IntRect boxRect(0, 0, containerBox->layer()->width(), containerBox->layer()->height());
1087         rect = intersection(repaintRect, boxRect);
1088         if (rect.isEmpty())
1089             return;
1090     } else
1091         rect.setLocation(topLeft);
1092 
1093     if (containerSkipped) {
1094         // If the repaintContainer is below o, then we need to map the rect into repaintContainer's coordinates.
1095         IntSize containerOffset = repaintContainer->offsetFromAncestorContainer(o);
1096         rect.move(-containerOffset);
1097         return;
1098     }
1099 
1100     o->computeRectForRepaint(repaintContainer, rect, fixed);
1101 }
1102 
offsetFromContainer(RenderObject * container,const IntPoint & point) const1103 IntSize RenderInline::offsetFromContainer(RenderObject* container, const IntPoint& point) const
1104 {
1105     ASSERT(container == this->container());
1106 
1107     IntSize offset;
1108     if (isRelPositioned())
1109         offset += relativePositionOffset();
1110 
1111     container->adjustForColumns(offset, point);
1112 
1113     if (container->hasOverflowClip())
1114         offset -= toRenderBox(container)->layer()->scrolledContentOffset();
1115 
1116     return offset;
1117 }
1118 
mapLocalToContainer(RenderBoxModelObject * repaintContainer,bool fixed,bool useTransforms,TransformState & transformState) const1119 void RenderInline::mapLocalToContainer(RenderBoxModelObject* repaintContainer, bool fixed, bool useTransforms, TransformState& transformState) const
1120 {
1121     if (repaintContainer == this)
1122         return;
1123 
1124     if (RenderView *v = view()) {
1125         if (v->layoutStateEnabled() && !repaintContainer) {
1126             LayoutState* layoutState = v->layoutState();
1127             IntSize offset = layoutState->m_paintOffset;
1128             if (style()->position() == RelativePosition && layer())
1129                 offset += layer()->relativePositionOffset();
1130             transformState.move(offset);
1131             return;
1132         }
1133     }
1134 
1135     bool containerSkipped;
1136     RenderObject* o = container(repaintContainer, &containerSkipped);
1137     if (!o)
1138         return;
1139 
1140     IntPoint centerPoint = roundedIntPoint(transformState.mappedPoint());
1141     if (o->isBox() && o->style()->isFlippedBlocksWritingMode())
1142         transformState.move(toRenderBox(o)->flipForWritingModeIncludingColumns(roundedIntPoint(transformState.mappedPoint())) - centerPoint);
1143 
1144     IntSize containerOffset = offsetFromContainer(o, roundedIntPoint(transformState.mappedPoint()));
1145 
1146     bool preserve3D = useTransforms && (o->style()->preserves3D() || style()->preserves3D());
1147     if (useTransforms && shouldUseTransformFromContainer(o)) {
1148         TransformationMatrix t;
1149         getTransformFromContainer(o, containerOffset, t);
1150         transformState.applyTransform(t, preserve3D ? TransformState::AccumulateTransform : TransformState::FlattenTransform);
1151     } else
1152         transformState.move(containerOffset.width(), containerOffset.height(), preserve3D ? TransformState::AccumulateTransform : TransformState::FlattenTransform);
1153 
1154     if (containerSkipped) {
1155         // There can't be a transform between repaintContainer and o, because transforms create containers, so it should be safe
1156         // to just subtract the delta between the repaintContainer and o.
1157         IntSize containerOffset = repaintContainer->offsetFromAncestorContainer(o);
1158         transformState.move(-containerOffset.width(), -containerOffset.height(), preserve3D ? TransformState::AccumulateTransform : TransformState::FlattenTransform);
1159         return;
1160     }
1161 
1162     o->mapLocalToContainer(repaintContainer, fixed, useTransforms, transformState);
1163 }
1164 
mapAbsoluteToLocalPoint(bool fixed,bool useTransforms,TransformState & transformState) const1165 void RenderInline::mapAbsoluteToLocalPoint(bool fixed, bool useTransforms, TransformState& transformState) const
1166 {
1167     // We don't expect this function to be called during layout.
1168     ASSERT(!view() || !view()->layoutStateEnabled());
1169 
1170     RenderObject* o = container();
1171     if (!o)
1172         return;
1173 
1174     o->mapAbsoluteToLocalPoint(fixed, useTransforms, transformState);
1175 
1176     IntSize containerOffset = offsetFromContainer(o, IntPoint());
1177 
1178     bool preserve3D = useTransforms && (o->style()->preserves3D() || style()->preserves3D());
1179     if (useTransforms && shouldUseTransformFromContainer(o)) {
1180         TransformationMatrix t;
1181         getTransformFromContainer(o, containerOffset, t);
1182         transformState.applyTransform(t, preserve3D ? TransformState::AccumulateTransform : TransformState::FlattenTransform);
1183     } else
1184         transformState.move(-containerOffset.width(), -containerOffset.height(), preserve3D ? TransformState::AccumulateTransform : TransformState::FlattenTransform);
1185 }
1186 
updateDragState(bool dragOn)1187 void RenderInline::updateDragState(bool dragOn)
1188 {
1189     RenderBoxModelObject::updateDragState(dragOn);
1190     if (continuation())
1191         continuation()->updateDragState(dragOn);
1192 }
1193 
childBecameNonInline(RenderObject * child)1194 void RenderInline::childBecameNonInline(RenderObject* child)
1195 {
1196     // We have to split the parent flow.
1197     RenderBlock* newBox = containingBlock()->createAnonymousBlock();
1198     RenderBoxModelObject* oldContinuation = continuation();
1199     setContinuation(newBox);
1200     RenderObject* beforeChild = child->nextSibling();
1201     children()->removeChildNode(this, child);
1202     splitFlow(beforeChild, newBox, child, oldContinuation);
1203 }
1204 
updateHitTestResult(HitTestResult & result,const IntPoint & point)1205 void RenderInline::updateHitTestResult(HitTestResult& result, const IntPoint& point)
1206 {
1207     if (result.innerNode())
1208         return;
1209 
1210     Node* n = node();
1211     IntPoint localPoint(point);
1212     if (n) {
1213         if (isInlineElementContinuation()) {
1214             // We're in the continuation of a split inline.  Adjust our local point to be in the coordinate space
1215             // of the principal renderer's containing block.  This will end up being the innerNonSharedNode.
1216             RenderBlock* firstBlock = n->renderer()->containingBlock();
1217 
1218             // Get our containing block.
1219             RenderBox* block = containingBlock();
1220             localPoint.move(block->x() - firstBlock->x(), block->y() - firstBlock->y());
1221         }
1222 
1223         result.setInnerNode(n);
1224         if (!result.innerNonSharedNode())
1225             result.setInnerNonSharedNode(n);
1226         result.setLocalPoint(localPoint);
1227     }
1228 }
1229 
dirtyLineBoxes(bool fullLayout)1230 void RenderInline::dirtyLineBoxes(bool fullLayout)
1231 {
1232     if (fullLayout) {
1233         m_lineBoxes.deleteLineBoxes(renderArena());
1234         return;
1235     }
1236 
1237     if (!alwaysCreateLineBoxes()) {
1238         // We have to grovel into our children in order to dirty the appropriate lines.
1239         for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) {
1240             if (curr->isFloatingOrPositioned())
1241                 continue;
1242             if (curr->isBox() && !curr->needsLayout()) {
1243                 RenderBox* currBox = toRenderBox(curr);
1244                 if (currBox->inlineBoxWrapper())
1245                     currBox->inlineBoxWrapper()->root()->markDirty();
1246             } else if (!curr->selfNeedsLayout()) {
1247                 if (curr->isRenderInline()) {
1248                     RenderInline* currInline = toRenderInline(curr);
1249                     for (InlineFlowBox* childLine = currInline->firstLineBox(); childLine; childLine = childLine->nextLineBox())
1250                         childLine->root()->markDirty();
1251                 } else if (curr->isText()) {
1252                     RenderText* currText = toRenderText(curr);
1253                     for (InlineTextBox* childText = currText->firstTextBox(); childText; childText = childText->nextTextBox())
1254                         childText->root()->markDirty();
1255                 }
1256             }
1257         }
1258     } else
1259         m_lineBoxes.dirtyLineBoxes();
1260 }
1261 
createInlineFlowBox()1262 InlineFlowBox* RenderInline::createInlineFlowBox()
1263 {
1264     return new (renderArena()) InlineFlowBox(this);
1265 }
1266 
createAndAppendInlineFlowBox()1267 InlineFlowBox* RenderInline::createAndAppendInlineFlowBox()
1268 {
1269     setAlwaysCreateLineBoxes();
1270     InlineFlowBox* flowBox = createInlineFlowBox();
1271     m_lineBoxes.appendLineBox(flowBox);
1272     return flowBox;
1273 }
1274 
lineHeight(bool firstLine,LineDirectionMode,LinePositionMode) const1275 int RenderInline::lineHeight(bool firstLine, LineDirectionMode /*direction*/, LinePositionMode /*linePositionMode*/) const
1276 {
1277     if (firstLine && document()->usesFirstLineRules()) {
1278         RenderStyle* s = style(firstLine);
1279         if (s != style())
1280             return s->computedLineHeight();
1281     }
1282 
1283     if (m_lineHeight == -1)
1284         m_lineHeight = style()->computedLineHeight();
1285 
1286     return m_lineHeight;
1287 }
1288 
baselinePosition(FontBaseline baselineType,bool firstLine,LineDirectionMode direction,LinePositionMode linePositionMode) const1289 int RenderInline::baselinePosition(FontBaseline baselineType, bool firstLine, LineDirectionMode direction, LinePositionMode linePositionMode) const
1290 {
1291     const FontMetrics& fontMetrics = style(firstLine)->fontMetrics();
1292     return fontMetrics.ascent(baselineType) + (lineHeight(firstLine, direction, linePositionMode) - fontMetrics.height()) / 2;
1293 }
1294 
relativePositionedInlineOffset(const RenderBox * child) const1295 IntSize RenderInline::relativePositionedInlineOffset(const RenderBox* child) const
1296 {
1297     // FIXME: This function isn't right with mixed writing modes.
1298 
1299     ASSERT(isRelPositioned());
1300     if (!isRelPositioned())
1301         return IntSize();
1302 
1303     // When we have an enclosing relpositioned inline, we need to add in the offset of the first line
1304     // box from the rest of the content, but only in the cases where we know we're positioned
1305     // relative to the inline itself.
1306 
1307     IntSize logicalOffset;
1308     int inlinePosition;
1309     int blockPosition;
1310     if (firstLineBox()) {
1311         inlinePosition = lroundf(firstLineBox()->logicalLeft());
1312         blockPosition = firstLineBox()->logicalTop();
1313     } else {
1314         inlinePosition = layer()->staticInlinePosition();
1315         blockPosition = layer()->staticBlockPosition();
1316     }
1317 
1318     if (!child->style()->hasStaticInlinePosition(style()->isHorizontalWritingMode()))
1319         logicalOffset.setWidth(inlinePosition);
1320 
1321     // This is not terribly intuitive, but we have to match other browsers.  Despite being a block display type inside
1322     // an inline, we still keep our x locked to the left of the relative positioned inline.  Arguably the correct
1323     // behavior would be to go flush left to the block that contains the inline, but that isn't what other browsers
1324     // do.
1325     else if (!child->style()->isOriginalDisplayInlineType())
1326         // Avoid adding in the left border/padding of the containing block twice.  Subtract it out.
1327         logicalOffset.setWidth(inlinePosition - child->containingBlock()->borderAndPaddingLogicalLeft());
1328 
1329     if (!child->style()->hasStaticBlockPosition(style()->isHorizontalWritingMode()))
1330         logicalOffset.setHeight(blockPosition);
1331 
1332     return style()->isHorizontalWritingMode() ? logicalOffset : logicalOffset.transposedSize();
1333 }
1334 
imageChanged(WrappedImagePtr,const IntRect *)1335 void RenderInline::imageChanged(WrappedImagePtr, const IntRect*)
1336 {
1337     if (!parent())
1338         return;
1339 
1340     // FIXME: We can do better.
1341     repaint();
1342 }
1343 
addFocusRingRects(Vector<IntRect> & rects,int tx,int ty)1344 void RenderInline::addFocusRingRects(Vector<IntRect>& rects, int tx, int ty)
1345 {
1346     if (!alwaysCreateLineBoxes())
1347         culledInlineAbsoluteRects(this, rects, IntSize(tx, ty));
1348     else {
1349         for (InlineFlowBox* curr = firstLineBox(); curr; curr = curr->nextLineBox())
1350             rects.append(enclosingIntRect(FloatRect(tx + curr->x(), ty + curr->y(), curr->width(), curr->height())));
1351     }
1352 
1353     for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) {
1354         if (!curr->isText() && !curr->isListMarker()) {
1355             FloatPoint pos(tx, ty);
1356             // FIXME: This doesn't work correctly with transforms.
1357             if (curr->hasLayer())
1358                 pos = curr->localToAbsolute();
1359             else if (curr->isBox())
1360                 pos.move(toRenderBox(curr)->x(), toRenderBox(curr)->y());
1361             curr->addFocusRingRects(rects, pos.x(), pos.y());
1362         }
1363     }
1364 
1365     if (continuation()) {
1366         if (continuation()->isInline())
1367             continuation()->addFocusRingRects(rects,
1368                                               tx - containingBlock()->x() + continuation()->containingBlock()->x(),
1369                                               ty - containingBlock()->y() + continuation()->containingBlock()->y());
1370         else
1371             continuation()->addFocusRingRects(rects,
1372                                               tx - containingBlock()->x() + toRenderBox(continuation())->x(),
1373                                               ty - containingBlock()->y() + toRenderBox(continuation())->y());
1374     }
1375 }
1376 
paintOutline(GraphicsContext * graphicsContext,int tx,int ty)1377 void RenderInline::paintOutline(GraphicsContext* graphicsContext, int tx, int ty)
1378 {
1379     if (!hasOutline())
1380         return;
1381 
1382     RenderStyle* styleToUse = style();
1383     if (styleToUse->outlineStyleIsAuto() || hasOutlineAnnotation()) {
1384         if (!theme()->supportsFocusRing(styleToUse)) {
1385             // Only paint the focus ring by hand if the theme isn't able to draw the focus ring.
1386             paintFocusRing(graphicsContext, tx, ty, styleToUse);
1387         }
1388     }
1389 
1390     if (styleToUse->outlineStyleIsAuto() || styleToUse->outlineStyle() == BNONE)
1391         return;
1392 
1393     Vector<IntRect> rects;
1394 
1395     rects.append(IntRect());
1396     for (InlineFlowBox* curr = firstLineBox(); curr; curr = curr->nextLineBox()) {
1397         RootInlineBox* root = curr->root();
1398         int top = max(root->lineTop(), curr->logicalTop());
1399         int bottom = min(root->lineBottom(), curr->logicalBottom());
1400         rects.append(IntRect(curr->x(), top, curr->logicalWidth(), bottom - top));
1401     }
1402     rects.append(IntRect());
1403 
1404     for (unsigned i = 1; i < rects.size() - 1; i++)
1405         paintOutlineForLine(graphicsContext, tx, ty, rects.at(i - 1), rects.at(i), rects.at(i + 1));
1406 }
1407 
paintOutlineForLine(GraphicsContext * graphicsContext,int tx,int ty,const IntRect & lastline,const IntRect & thisline,const IntRect & nextline)1408 void RenderInline::paintOutlineForLine(GraphicsContext* graphicsContext, int tx, int ty,
1409                                        const IntRect& lastline, const IntRect& thisline, const IntRect& nextline)
1410 {
1411     RenderStyle* styleToUse = style();
1412     int ow = styleToUse->outlineWidth();
1413     EBorderStyle os = styleToUse->outlineStyle();
1414     Color oc = styleToUse->visitedDependentColor(CSSPropertyOutlineColor);
1415 
1416     int offset = style()->outlineOffset();
1417 
1418     int t = ty + thisline.y() - offset;
1419     int l = tx + thisline.x() - offset;
1420     int b = ty + thisline.maxY() + offset;
1421     int r = tx + thisline.maxX() + offset;
1422 
1423     // left edge
1424     drawLineForBoxSide(graphicsContext,
1425                l - ow,
1426                t - (lastline.isEmpty() || thisline.x() < lastline.x() || (lastline.maxX() - 1) <= thisline.x() ? ow : 0),
1427                l,
1428                b + (nextline.isEmpty() || thisline.x() <= nextline.x() || (nextline.maxX() - 1) <= thisline.x() ? ow : 0),
1429                BSLeft,
1430                oc, os,
1431                (lastline.isEmpty() || thisline.x() < lastline.x() || (lastline.maxX() - 1) <= thisline.x() ? ow : -ow),
1432                (nextline.isEmpty() || thisline.x() <= nextline.x() || (nextline.maxX() - 1) <= thisline.x() ? ow : -ow));
1433 
1434     // right edge
1435     drawLineForBoxSide(graphicsContext,
1436                r,
1437                t - (lastline.isEmpty() || lastline.maxX() < thisline.maxX() || (thisline.maxX() - 1) <= lastline.x() ? ow : 0),
1438                r + ow,
1439                b + (nextline.isEmpty() || nextline.maxX() <= thisline.maxX() || (thisline.maxX() - 1) <= nextline.x() ? ow : 0),
1440                BSRight,
1441                oc, os,
1442                (lastline.isEmpty() || lastline.maxX() < thisline.maxX() || (thisline.maxX() - 1) <= lastline.x() ? ow : -ow),
1443                (nextline.isEmpty() || nextline.maxX() <= thisline.maxX() || (thisline.maxX() - 1) <= nextline.x() ? ow : -ow));
1444     // upper edge
1445     if (thisline.x() < lastline.x())
1446         drawLineForBoxSide(graphicsContext,
1447                    l - ow,
1448                    t - ow,
1449                    min(r+ow, (lastline.isEmpty() ? 1000000 : tx + lastline.x())),
1450                    t ,
1451                    BSTop, oc, os,
1452                    ow,
1453                    (!lastline.isEmpty() && tx + lastline.x() + 1 < r + ow) ? -ow : ow);
1454 
1455     if (lastline.maxX() < thisline.maxX())
1456         drawLineForBoxSide(graphicsContext,
1457                    max(lastline.isEmpty() ? -1000000 : tx + lastline.maxX(), l - ow),
1458                    t - ow,
1459                    r + ow,
1460                    t ,
1461                    BSTop, oc, os,
1462                    (!lastline.isEmpty() && l - ow < tx + lastline.maxX()) ? -ow : ow,
1463                    ow);
1464 
1465     // lower edge
1466     if (thisline.x() < nextline.x())
1467         drawLineForBoxSide(graphicsContext,
1468                    l - ow,
1469                    b,
1470                    min(r + ow, !nextline.isEmpty() ? tx + nextline.x() + 1 : 1000000),
1471                    b + ow,
1472                    BSBottom, oc, os,
1473                    ow,
1474                    (!nextline.isEmpty() && tx + nextline.x() + 1 < r + ow) ? -ow : ow);
1475 
1476     if (nextline.maxX() < thisline.maxX())
1477         drawLineForBoxSide(graphicsContext,
1478                    max(!nextline.isEmpty() ? tx + nextline.maxX() : -1000000, l - ow),
1479                    b,
1480                    r + ow,
1481                    b + ow,
1482                    BSBottom, oc, os,
1483                    (!nextline.isEmpty() && l - ow < tx + nextline.maxX()) ? -ow : ow,
1484                    ow);
1485 }
1486 
1487 #if ENABLE(DASHBOARD_SUPPORT)
addDashboardRegions(Vector<DashboardRegionValue> & regions)1488 void RenderInline::addDashboardRegions(Vector<DashboardRegionValue>& regions)
1489 {
1490     // Convert the style regions to absolute coordinates.
1491     if (style()->visibility() != VISIBLE)
1492         return;
1493 
1494     const Vector<StyleDashboardRegion>& styleRegions = style()->dashboardRegions();
1495     unsigned i, count = styleRegions.size();
1496     for (i = 0; i < count; i++) {
1497         StyleDashboardRegion styleRegion = styleRegions[i];
1498 
1499         IntRect linesBoundingBox = this->linesBoundingBox();
1500         int w = linesBoundingBox.width();
1501         int h = linesBoundingBox.height();
1502 
1503         DashboardRegionValue region;
1504         region.label = styleRegion.label;
1505         region.bounds = IntRect(linesBoundingBox.x() + styleRegion.offset.left().value(),
1506                                 linesBoundingBox.y() + styleRegion.offset.top().value(),
1507                                 w - styleRegion.offset.left().value() - styleRegion.offset.right().value(),
1508                                 h - styleRegion.offset.top().value() - styleRegion.offset.bottom().value());
1509         region.type = styleRegion.type;
1510 
1511         RenderObject* container = containingBlock();
1512         if (!container)
1513             container = this;
1514 
1515         region.clip = region.bounds;
1516         container->computeAbsoluteRepaintRect(region.clip);
1517         if (region.clip.height() < 0) {
1518             region.clip.setHeight(0);
1519             region.clip.setWidth(0);
1520         }
1521 
1522         FloatPoint absPos = container->localToAbsolute();
1523         region.bounds.setX(absPos.x() + region.bounds.x());
1524         region.bounds.setY(absPos.y() + region.bounds.y());
1525 
1526         if (frame()) {
1527             float pageScaleFactor = frame()->page()->chrome()->scaleFactor();
1528             if (pageScaleFactor != 1.0f) {
1529                 region.bounds.scale(pageScaleFactor);
1530                 region.clip.scale(pageScaleFactor);
1531             }
1532         }
1533 
1534         regions.append(region);
1535     }
1536 }
1537 #endif
1538 
1539 } // namespace WebCore
1540