• 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 "FloatQuad.h"
27 #include "GraphicsContext.h"
28 #include "HitTestResult.h"
29 #include "Page.h"
30 #include "RenderArena.h"
31 #include "RenderBlock.h"
32 #include "RenderView.h"
33 #include "VisiblePosition.h"
34 
35 #if ENABLE(DASHBOARD_SUPPORT)
36 #include "Frame.h"
37 #endif
38 
39 using namespace std;
40 
41 namespace WebCore {
42 
RenderInline(Node * node)43 RenderInline::RenderInline(Node* node)
44     : RenderBoxModelObject(node)
45     , m_continuation(0)
46     , m_lineHeight(-1)
47     , m_verticalPosition(PositionUndefined)
48 {
49     setChildrenInline(true);
50 }
51 
destroy()52 void RenderInline::destroy()
53 {
54     // Make sure to destroy anonymous children first while they are still connected to the rest of the tree, so that they will
55     // properly dirty line boxes that they are removed from.  Effects that do :before/:after only on hover could crash otherwise.
56     children()->destroyLeftoverChildren();
57 
58     // Destroy our continuation before anything other than anonymous children.
59     // The reason we don't destroy it before anonymous children is that they may
60     // have continuations of their own that are anonymous children of our continuation.
61     if (m_continuation) {
62         m_continuation->destroy();
63         m_continuation = 0;
64     }
65 
66     if (!documentBeingDestroyed()) {
67         if (firstLineBox()) {
68             // We can't wait for RenderBoxModelObject::destroy to clear the selection,
69             // because by then we will have nuked the line boxes.
70             // FIXME: The SelectionController should be responsible for this when it
71             // is notified of DOM mutations.
72             if (isSelectionBorder())
73                 view()->clearSelection();
74 
75             // If line boxes are contained inside a root, that means we're an inline.
76             // In that case, we need to remove all the line boxes so that the parent
77             // lines aren't pointing to deleted children. If the first line box does
78             // not have a parent that means they are either already disconnected or
79             // root lines that can just be destroyed without disconnecting.
80             if (firstLineBox()->parent()) {
81                 for (InlineRunBox* box = firstLineBox(); box; box = box->nextLineBox())
82                     box->remove();
83             }
84         } else if (isInline() && parent())
85             parent()->dirtyLinesFromChangedChild(this);
86     }
87 
88     m_lineBoxes.deleteLineBoxes(renderArena());
89 
90     RenderBoxModelObject::destroy();
91 }
92 
inlineContinuation() const93 RenderInline* RenderInline::inlineContinuation() const
94 {
95     if (!m_continuation || m_continuation->isInline())
96         return toRenderInline(m_continuation);
97     return toRenderBlock(m_continuation)->inlineContinuation();
98 }
99 
updateBoxModelInfoFromStyle()100 void RenderInline::updateBoxModelInfoFromStyle()
101 {
102     RenderBoxModelObject::updateBoxModelInfoFromStyle();
103 
104     setInline(true); // Needed for run-ins, since run-in is considered a block display type.
105 
106     // FIXME: Support transforms and reflections on inline flows someday.
107     setHasTransform(false);
108     setHasReflection(false);
109 }
110 
styleDidChange(StyleDifference diff,const RenderStyle * oldStyle)111 void RenderInline::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
112 {
113     RenderBoxModelObject::styleDidChange(diff, oldStyle);
114 
115     // Ensure that all of the split inlines pick up the new style. We
116     // only do this if we're an inline, since we don't want to propagate
117     // a block's style to the other inlines.
118     // e.g., <font>foo <h4>goo</h4> moo</font>.  The <font> inlines before
119     // and after the block share the same style, but the block doesn't
120     // need to pass its style on to anyone else.
121     for (RenderInline* currCont = inlineContinuation(); currCont; currCont = currCont->inlineContinuation()) {
122         RenderBoxModelObject* nextCont = currCont->continuation();
123         currCont->setContinuation(0);
124         currCont->setStyle(style());
125         currCont->setContinuation(nextCont);
126     }
127 
128     m_lineHeight = -1;
129 
130     // Update pseudos for :before and :after now.
131     if (!isAnonymous() && document()->usesBeforeAfterRules()) {
132         children()->updateBeforeAfterContent(this, BEFORE);
133         children()->updateBeforeAfterContent(this, AFTER);
134     }
135 }
136 
isAfterContent(RenderObject * child)137 static inline bool isAfterContent(RenderObject* child)
138 {
139     if (!child)
140         return false;
141     if (child->style()->styleType() != AFTER)
142         return false;
143     // Text nodes don't have their own styles, so ignore the style on a text node.
144     if (child->isText() && !child->isBR())
145         return false;
146     return true;
147 }
148 
addChild(RenderObject * newChild,RenderObject * beforeChild)149 void RenderInline::addChild(RenderObject* newChild, RenderObject* beforeChild)
150 {
151     if (continuation())
152         return addChildToContinuation(newChild, beforeChild);
153     return addChildIgnoringContinuation(newChild, beforeChild);
154 }
155 
nextContinuation(RenderObject * renderer)156 static RenderBoxModelObject* nextContinuation(RenderObject* renderer)
157 {
158     if (renderer->isInline() && !renderer->isReplaced())
159         return toRenderInline(renderer)->continuation();
160     return toRenderBlock(renderer)->inlineContinuation();
161 }
162 
continuationBefore(RenderObject * beforeChild)163 RenderBoxModelObject* RenderInline::continuationBefore(RenderObject* beforeChild)
164 {
165     if (beforeChild && beforeChild->parent() == this)
166         return this;
167 
168     RenderBoxModelObject* curr = nextContinuation(this);
169     RenderBoxModelObject* nextToLast = this;
170     RenderBoxModelObject* last = this;
171     while (curr) {
172         if (beforeChild && beforeChild->parent() == curr) {
173             if (curr->firstChild() == beforeChild)
174                 return last;
175             return curr;
176         }
177 
178         nextToLast = last;
179         last = curr;
180         curr = nextContinuation(curr);
181     }
182 
183     if (!beforeChild && !last->firstChild())
184         return nextToLast;
185     return last;
186 }
187 
addChildIgnoringContinuation(RenderObject * newChild,RenderObject * beforeChild)188 void RenderInline::addChildIgnoringContinuation(RenderObject* newChild, RenderObject* beforeChild)
189 {
190     // Make sure we don't append things after :after-generated content if we have it.
191     if (!beforeChild && isAfterContent(lastChild()))
192         beforeChild = lastChild();
193 
194     if (!newChild->isInline() && !newChild->isFloatingOrPositioned()) {
195         // We are placing a block inside an inline. We have to perform a split of this
196         // inline into continuations.  This involves creating an anonymous block box to hold
197         // |newChild|.  We then make that block box a continuation of this inline.  We take all of
198         // the children after |beforeChild| and put them in a clone of this object.
199         RefPtr<RenderStyle> newStyle = RenderStyle::create();
200         newStyle->inheritFrom(style());
201         newStyle->setDisplay(BLOCK);
202 
203         RenderBlock* newBox = new (renderArena()) RenderBlock(document() /* anonymous box */);
204         newBox->setStyle(newStyle.release());
205         RenderBoxModelObject* oldContinuation = continuation();
206         setContinuation(newBox);
207 
208         // Someone may have put a <p> inside a <q>, causing a split.  When this happens, the :after content
209         // has to move into the inline continuation.  Call updateBeforeAfterContent to ensure that our :after
210         // content gets properly destroyed.
211         bool isLastChild = (beforeChild == lastChild());
212         if (document()->usesBeforeAfterRules())
213             children()->updateBeforeAfterContent(this, AFTER);
214         if (isLastChild && beforeChild != lastChild())
215             beforeChild = 0; // We destroyed the last child, so now we need to update our insertion
216                              // point to be 0.  It's just a straight append now.
217 
218         splitFlow(beforeChild, newBox, newChild, oldContinuation);
219         return;
220     }
221 
222     RenderBoxModelObject::addChild(newChild, beforeChild);
223 
224     newChild->setNeedsLayoutAndPrefWidthsRecalc();
225 }
226 
cloneInline(RenderInline * src)227 RenderInline* RenderInline::cloneInline(RenderInline* src)
228 {
229     RenderInline* o = new (src->renderArena()) RenderInline(src->node());
230     o->setStyle(src->style());
231     return o;
232 }
233 
splitInlines(RenderBlock * fromBlock,RenderBlock * toBlock,RenderBlock * middleBlock,RenderObject * beforeChild,RenderBoxModelObject * oldCont)234 void RenderInline::splitInlines(RenderBlock* fromBlock, RenderBlock* toBlock,
235                                 RenderBlock* middleBlock,
236                                 RenderObject* beforeChild, RenderBoxModelObject* oldCont)
237 {
238     // Create a clone of this inline.
239     RenderInline* clone = cloneInline(this);
240     clone->setContinuation(oldCont);
241 
242     // Now take all of the children from beforeChild to the end and remove
243     // them from |this| and place them in the clone.
244     RenderObject* o = beforeChild;
245     while (o) {
246         RenderObject* tmp = o;
247         o = tmp->nextSibling();
248         clone->addChildIgnoringContinuation(children()->removeChildNode(this, tmp), 0);
249         tmp->setNeedsLayoutAndPrefWidthsRecalc();
250     }
251 
252     // Hook |clone| up as the continuation of the middle block.
253     middleBlock->setInlineContinuation(clone);
254 
255     // We have been reparented and are now under the fromBlock.  We need
256     // to walk up our inline parent chain until we hit the containing block.
257     // Once we hit the containing block we're done.
258     RenderBoxModelObject* curr = toRenderBoxModelObject(parent());
259     RenderBoxModelObject* currChild = this;
260 
261     // FIXME: Because splitting is O(n^2) as tags nest pathologically, we cap the depth at which we're willing to clone.
262     // There will eventually be a better approach to this problem that will let us nest to a much
263     // greater depth (see bugzilla bug 13430) but for now we have a limit.  This *will* result in
264     // incorrect rendering, but the alternative is to hang forever.
265     unsigned splitDepth = 1;
266     const unsigned cMaxSplitDepth = 200;
267     while (curr && curr != fromBlock) {
268         ASSERT(curr->isRenderInline());
269         if (splitDepth < cMaxSplitDepth) {
270             // Create a new clone.
271             RenderInline* cloneChild = clone;
272             clone = cloneInline(toRenderInline(curr));
273 
274             // Insert our child clone as the first child.
275             clone->addChildIgnoringContinuation(cloneChild, 0);
276 
277             // Hook the clone up as a continuation of |curr|.
278             RenderInline* inlineCurr = toRenderInline(curr);
279             oldCont = inlineCurr->continuation();
280             inlineCurr->setContinuation(clone);
281             clone->setContinuation(oldCont);
282 
283             // Someone may have indirectly caused a <q> to split.  When this happens, the :after content
284             // has to move into the inline continuation.  Call updateBeforeAfterContent to ensure that the inline's :after
285             // content gets properly destroyed.
286             if (document()->usesBeforeAfterRules())
287                 inlineCurr->children()->updateBeforeAfterContent(this, AFTER);
288 
289             // Now we need to take all of the children starting from the first child
290             // *after* currChild and append them all to the clone.
291             o = currChild->nextSibling();
292             while (o) {
293                 RenderObject* tmp = o;
294                 o = tmp->nextSibling();
295                 clone->addChildIgnoringContinuation(inlineCurr->children()->removeChildNode(curr, tmp), 0);
296                 tmp->setNeedsLayoutAndPrefWidthsRecalc();
297             }
298         }
299 
300         // Keep walking up the chain.
301         currChild = curr;
302         curr = toRenderBoxModelObject(curr->parent());
303         splitDepth++;
304     }
305 
306     // Now we are at the block level. We need to put the clone into the toBlock.
307     toBlock->children()->appendChildNode(toBlock, clone);
308 
309     // Now take all the children after currChild and remove them from the fromBlock
310     // and put them in the toBlock.
311     o = currChild->nextSibling();
312     while (o) {
313         RenderObject* tmp = o;
314         o = tmp->nextSibling();
315         toBlock->children()->appendChildNode(toBlock, fromBlock->children()->removeChildNode(fromBlock, tmp));
316     }
317 }
318 
splitFlow(RenderObject * beforeChild,RenderBlock * newBlockBox,RenderObject * newChild,RenderBoxModelObject * oldCont)319 void RenderInline::splitFlow(RenderObject* beforeChild, RenderBlock* newBlockBox,
320                              RenderObject* newChild, RenderBoxModelObject* oldCont)
321 {
322     RenderBlock* pre = 0;
323     RenderBlock* block = containingBlock();
324 
325     // Delete our line boxes before we do the inline split into continuations.
326     block->deleteLineBoxTree();
327 
328     bool madeNewBeforeBlock = false;
329     if (block->isAnonymousBlock() && (!block->parent() || !block->parent()->createsAnonymousWrapper())) {
330         // We can reuse this block and make it the preBlock of the next continuation.
331         pre = block;
332         pre->removePositionedObjects(0);
333         block = block->containingBlock();
334     } else {
335         // No anonymous block available for use.  Make one.
336         pre = block->createAnonymousBlock();
337         madeNewBeforeBlock = true;
338     }
339 
340     RenderBlock* post = block->createAnonymousBlock();
341 
342     RenderObject* boxFirst = madeNewBeforeBlock ? block->firstChild() : pre->nextSibling();
343     if (madeNewBeforeBlock)
344         block->children()->insertChildNode(block, pre, boxFirst);
345     block->children()->insertChildNode(block, newBlockBox, boxFirst);
346     block->children()->insertChildNode(block, post, boxFirst);
347     block->setChildrenInline(false);
348 
349     if (madeNewBeforeBlock) {
350         RenderObject* o = boxFirst;
351         while (o) {
352             RenderObject* no = o;
353             o = no->nextSibling();
354             pre->children()->appendChildNode(pre, block->children()->removeChildNode(block, no));
355             no->setNeedsLayoutAndPrefWidthsRecalc();
356         }
357     }
358 
359     splitInlines(pre, post, newBlockBox, beforeChild, oldCont);
360 
361     // We already know the newBlockBox isn't going to contain inline kids, so avoid wasting
362     // time in makeChildrenNonInline by just setting this explicitly up front.
363     newBlockBox->setChildrenInline(false);
364 
365     // We delayed adding the newChild until now so that the |newBlockBox| would be fully
366     // connected, thus allowing newChild access to a renderArena should it need
367     // to wrap itself in additional boxes (e.g., table construction).
368     newBlockBox->addChild(newChild);
369 
370     // Always just do a full layout in order to ensure that line boxes (especially wrappers for images)
371     // get deleted properly.  Because objects moves from the pre block into the post block, we want to
372     // make new line boxes instead of leaving the old line boxes around.
373     pre->setNeedsLayoutAndPrefWidthsRecalc();
374     block->setNeedsLayoutAndPrefWidthsRecalc();
375     post->setNeedsLayoutAndPrefWidthsRecalc();
376 }
377 
addChildToContinuation(RenderObject * newChild,RenderObject * beforeChild)378 void RenderInline::addChildToContinuation(RenderObject* newChild, RenderObject* beforeChild)
379 {
380     RenderBoxModelObject* flow = continuationBefore(beforeChild);
381     ASSERT(!beforeChild || beforeChild->parent()->isRenderBlock() || beforeChild->parent()->isRenderInline());
382     RenderBoxModelObject* beforeChildParent = 0;
383     if (beforeChild)
384         beforeChildParent = toRenderBoxModelObject(beforeChild->parent());
385     else {
386         RenderBoxModelObject* cont = nextContinuation(flow);
387         if (cont)
388             beforeChildParent = cont;
389         else
390             beforeChildParent = flow;
391     }
392 
393     if (newChild->isFloatingOrPositioned())
394         return beforeChildParent->addChildIgnoringContinuation(newChild, beforeChild);
395 
396     // A continuation always consists of two potential candidates: an inline or an anonymous
397     // block box holding block children.
398     bool childInline = newChild->isInline();
399     bool bcpInline = beforeChildParent->isInline();
400     bool flowInline = flow->isInline();
401 
402     if (flow == beforeChildParent)
403         return flow->addChildIgnoringContinuation(newChild, beforeChild);
404     else {
405         // The goal here is to match up if we can, so that we can coalesce and create the
406         // minimal # of continuations needed for the inline.
407         if (childInline == bcpInline)
408             return beforeChildParent->addChildIgnoringContinuation(newChild, beforeChild);
409         else if (flowInline == childInline)
410             return flow->addChildIgnoringContinuation(newChild, 0); // Just treat like an append.
411         else
412             return beforeChildParent->addChildIgnoringContinuation(newChild, beforeChild);
413     }
414 }
415 
paint(PaintInfo & paintInfo,int tx,int ty)416 void RenderInline::paint(PaintInfo& paintInfo, int tx, int ty)
417 {
418     m_lineBoxes.paint(this, paintInfo, tx, ty);
419 }
420 
absoluteRects(Vector<IntRect> & rects,int tx,int ty)421 void RenderInline::absoluteRects(Vector<IntRect>& rects, int tx, int ty)
422 {
423     if (InlineRunBox* curr = firstLineBox()) {
424         for (; curr; curr = curr->nextLineBox())
425             rects.append(IntRect(tx + curr->x(), ty + curr->y(), curr->width(), curr->height()));
426     } else
427         rects.append(IntRect(tx, ty, 0, 0));
428 
429     if (continuation()) {
430         if (continuation()->isBox()) {
431             RenderBox* box = toRenderBox(continuation());
432             continuation()->absoluteRects(rects,
433                                           tx - containingBlock()->x() + box->x(),
434                                           ty - containingBlock()->y() + box->y());
435         } else
436             continuation()->absoluteRects(rects, tx - containingBlock()->x(), ty - containingBlock()->y());
437     }
438 }
439 
absoluteQuads(Vector<FloatQuad> & quads)440 void RenderInline::absoluteQuads(Vector<FloatQuad>& quads)
441 {
442     if (InlineRunBox* curr = firstLineBox()) {
443         for (; curr; curr = curr->nextLineBox()) {
444             FloatRect localRect(curr->x(), curr->y(), curr->width(), curr->height());
445             quads.append(localToAbsoluteQuad(localRect));
446         }
447     } else
448         quads.append(localToAbsoluteQuad(FloatRect()));
449 
450     if (continuation())
451         continuation()->absoluteQuads(quads);
452 }
453 
offsetLeft() const454 int RenderInline::offsetLeft() const
455 {
456     int x = RenderBoxModelObject::offsetLeft();
457     if (firstLineBox())
458         x += firstLineBox()->x();
459     return x;
460 }
461 
offsetTop() const462 int RenderInline::offsetTop() const
463 {
464     int y = RenderBoxModelObject::offsetTop();
465     if (firstLineBox())
466         y += firstLineBox()->y();
467     return y;
468 }
469 
marginLeft() const470 int RenderInline::marginLeft() const
471 {
472     Length margin = style()->marginLeft();
473     if (margin.isAuto())
474         return 0;
475     if (margin.isFixed())
476         return margin.value();
477     if (margin.isPercent())
478         return margin.calcMinValue(max(0, containingBlock()->availableWidth()));
479     return 0;
480 }
481 
marginRight() const482 int RenderInline::marginRight() const
483 {
484     Length margin = style()->marginRight();
485     if (margin.isAuto())
486         return 0;
487     if (margin.isFixed())
488         return margin.value();
489     if (margin.isPercent())
490         return margin.calcMinValue(max(0, containingBlock()->availableWidth()));
491     return 0;
492 }
493 
renderName() const494 const char* RenderInline::renderName() const
495 {
496     if (isRelPositioned())
497         return "RenderInline (relative positioned)";
498     if (isAnonymous())
499         return "RenderInline (generated)";
500     if (isRunIn())
501         return "RenderInline (run-in)";
502     return "RenderInline";
503 }
504 
nodeAtPoint(const HitTestRequest & request,HitTestResult & result,int x,int y,int tx,int ty,HitTestAction hitTestAction)505 bool RenderInline::nodeAtPoint(const HitTestRequest& request, HitTestResult& result,
506                                 int x, int y, int tx, int ty, HitTestAction hitTestAction)
507 {
508     return m_lineBoxes.hitTest(this, request, result, x, y, tx, ty, hitTestAction);
509 }
510 
positionForPoint(const IntPoint & point)511 VisiblePosition RenderInline::positionForPoint(const IntPoint& point)
512 {
513     // FIXME: Does not deal with relative positioned inlines (should it?)
514     RenderBlock* cb = containingBlock();
515     if (firstLineBox()) {
516         // This inline actually has a line box.  We must have clicked in the border/padding of one of these boxes.  We
517         // should try to find a result by asking our containing block.
518         return cb->positionForPoint(point);
519     }
520 
521     // Translate the coords from the pre-anonymous block to the post-anonymous block.
522     int parentBlockX = cb->x() + point.x();
523     int parentBlockY = cb->y() + point.y();
524     RenderBoxModelObject* c = continuation();
525     while (c) {
526         RenderBox* contBlock = c->isInline() ? c->containingBlock() : toRenderBlock(c);
527         if (c->isInline() || c->firstChild())
528             return c->positionForCoordinates(parentBlockX - contBlock->x(), parentBlockY - contBlock->y());
529         c = toRenderBlock(c)->inlineContinuation();
530     }
531 
532     return RenderBoxModelObject::positionForPoint(point);
533 }
534 
linesBoundingBox() const535 IntRect RenderInline::linesBoundingBox() const
536 {
537     IntRect result;
538 
539     // 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
540     // 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
541     // builds and help us someday figure out why.  We also put in a redundant check of lastLineBox() to avoid the crash for now.
542     ASSERT(!firstLineBox() == !lastLineBox());  // Either both are null or both exist.
543     if (firstLineBox() && lastLineBox()) {
544         // Return the width of the minimal left side and the maximal right side.
545         int leftSide = 0;
546         int rightSide = 0;
547         for (InlineRunBox* curr = firstLineBox(); curr; curr = curr->nextLineBox()) {
548             if (curr == firstLineBox() || curr->x() < leftSide)
549                 leftSide = curr->x();
550             if (curr == firstLineBox() || curr->x() + curr->width() > rightSide)
551                 rightSide = curr->x() + curr->width();
552         }
553         result.setWidth(rightSide - leftSide);
554         result.setX(leftSide);
555         result.setHeight(lastLineBox()->y() + lastLineBox()->height() - firstLineBox()->y());
556         result.setY(firstLineBox()->y());
557     }
558 
559     return result;
560 }
561 
clippedOverflowRectForRepaint(RenderBoxModelObject * repaintContainer)562 IntRect RenderInline::clippedOverflowRectForRepaint(RenderBoxModelObject* repaintContainer)
563 {
564     // Only run-ins are allowed in here during layout.
565     ASSERT(!view() || !view()->layoutStateEnabled() || isRunIn());
566 
567     if (!firstLineBox() && !continuation())
568         return IntRect();
569 
570     // Find our leftmost position.
571     IntRect boundingBox(linesBoundingBox());
572     int left = boundingBox.x();
573     int top = boundingBox.y();
574 
575     // Now invalidate a rectangle.
576     int ow = style() ? style()->outlineSize() : 0;
577 
578     // We need to add in the relative position offsets of any inlines (including us) up to our
579     // containing block.
580     RenderBlock* cb = containingBlock();
581     for (RenderObject* inlineFlow = this; inlineFlow && inlineFlow->isRenderInline() && inlineFlow != cb;
582          inlineFlow = inlineFlow->parent()) {
583          if (inlineFlow->style()->position() == RelativePosition && inlineFlow->hasLayer())
584             toRenderInline(inlineFlow)->layer()->relativePositionOffset(left, top);
585     }
586 
587     IntRect r(-ow + left, -ow + top, boundingBox.width() + ow * 2, boundingBox.height() + ow * 2);
588     if (cb->hasColumns())
589         cb->adjustRectForColumns(r);
590 
591     if (cb->hasOverflowClip()) {
592         // cb->height() is inaccurate if we're in the middle of a layout of |cb|, so use the
593         // layer's size instead.  Even if the layer's size is wrong, the layer itself will repaint
594         // anyway if its size does change.
595         int x = r.x();
596         int y = r.y();
597         IntRect boxRect(0, 0, cb->layer()->width(), cb->layer()->height());
598         cb->layer()->subtractScrolledContentOffset(x, y); // For overflow:auto/scroll/hidden.
599         IntRect repaintRect(x, y, r.width(), r.height());
600         r = intersection(repaintRect, boxRect);
601     }
602 
603     // FIXME: need to ensure that we compute the correct repaint rect when the repaint container
604     // is an inline.
605     if (repaintContainer != this)
606         cb->computeRectForRepaint(repaintContainer, r);
607 
608     if (ow) {
609         for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) {
610             if (!curr->isText()) {
611                 IntRect childRect = curr->rectWithOutlineForRepaint(repaintContainer, ow);
612                 r.unite(childRect);
613             }
614         }
615 
616         if (continuation() && !continuation()->isInline()) {
617             IntRect contRect = continuation()->rectWithOutlineForRepaint(repaintContainer, ow);
618             r.unite(contRect);
619         }
620     }
621 
622     return r;
623 }
624 
rectWithOutlineForRepaint(RenderBoxModelObject * repaintContainer,int outlineWidth)625 IntRect RenderInline::rectWithOutlineForRepaint(RenderBoxModelObject* repaintContainer, int outlineWidth)
626 {
627     IntRect r(RenderBoxModelObject::rectWithOutlineForRepaint(repaintContainer, outlineWidth));
628     for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) {
629         if (!curr->isText())
630             r.unite(curr->rectWithOutlineForRepaint(repaintContainer, outlineWidth));
631     }
632     return r;
633 }
634 
computeRectForRepaint(RenderBoxModelObject * repaintContainer,IntRect & rect,bool fixed)635 void RenderInline::computeRectForRepaint(RenderBoxModelObject* repaintContainer, IntRect& rect, bool fixed)
636 {
637     if (RenderView* v = view()) {
638         // LayoutState is only valid for root-relative repainting
639         if (v->layoutStateEnabled() && !repaintContainer) {
640             LayoutState* layoutState = v->layoutState();
641             if (style()->position() == RelativePosition && layer())
642                 rect.move(layer()->relativePositionOffset());
643             rect.move(layoutState->m_offset);
644             if (layoutState->m_clipped)
645                 rect.intersect(layoutState->m_clipRect);
646             return;
647         }
648     }
649 
650     if (repaintContainer == this)
651         return;
652 
653     RenderObject* o = container();
654     if (!o)
655         return;
656 
657     IntPoint topLeft = rect.location();
658 
659     if (o->isBlockFlow() && style()->position() != AbsolutePosition && style()->position() != FixedPosition) {
660         RenderBlock* cb = toRenderBlock(o);
661         if (cb->hasColumns()) {
662             IntRect repaintRect(topLeft, rect.size());
663             cb->adjustRectForColumns(repaintRect);
664             topLeft = repaintRect.location();
665             rect = repaintRect;
666         }
667     }
668 
669     if (style()->position() == RelativePosition && layer()) {
670         // Apply the relative position offset when invalidating a rectangle.  The layer
671         // is translated, but the render box isn't, so we need to do this to get the
672         // right dirty rect.  Since this is called from RenderObject::setStyle, the relative position
673         // flag on the RenderObject has been cleared, so use the one on the style().
674         topLeft += layer()->relativePositionOffset();
675     }
676 
677     // FIXME: We ignore the lightweight clipping rect that controls use, since if |o| is in mid-layout,
678     // its controlClipRect will be wrong. For overflow clip we use the values cached by the layer.
679     if (o->hasOverflowClip()) {
680         RenderBox* containerBox = toRenderBox(o);
681 
682         // o->height() is inaccurate if we're in the middle of a layout of |o|, so use the
683         // layer's size instead.  Even if the layer's size is wrong, the layer itself will repaint
684         // anyway if its size does change.
685         topLeft -= containerBox->layer()->scrolledContentOffset(); // For overflow:auto/scroll/hidden.
686 
687         IntRect repaintRect(topLeft, rect.size());
688         IntRect boxRect(0, 0, containerBox->layer()->width(), containerBox->layer()->height());
689         rect = intersection(repaintRect, boxRect);
690         if (rect.isEmpty())
691             return;
692     } else
693         rect.setLocation(topLeft);
694 
695     o->computeRectForRepaint(repaintContainer, rect, fixed);
696 }
697 
updateDragState(bool dragOn)698 void RenderInline::updateDragState(bool dragOn)
699 {
700     RenderBoxModelObject::updateDragState(dragOn);
701     if (continuation())
702         continuation()->updateDragState(dragOn);
703 }
704 
childBecameNonInline(RenderObject * child)705 void RenderInline::childBecameNonInline(RenderObject* child)
706 {
707     // We have to split the parent flow.
708     RenderBlock* newBox = containingBlock()->createAnonymousBlock();
709     RenderBoxModelObject* oldContinuation = continuation();
710     setContinuation(newBox);
711     RenderObject* beforeChild = child->nextSibling();
712     children()->removeChildNode(this, child);
713     splitFlow(beforeChild, newBox, child, oldContinuation);
714 }
715 
updateHitTestResult(HitTestResult & result,const IntPoint & point)716 void RenderInline::updateHitTestResult(HitTestResult& result, const IntPoint& point)
717 {
718     if (result.innerNode())
719         return;
720 
721     Node* n = node();
722     IntPoint localPoint(point);
723     if (n) {
724         if (isInlineContinuation()) {
725             // We're in the continuation of a split inline.  Adjust our local point to be in the coordinate space
726             // of the principal renderer's containing block.  This will end up being the innerNonSharedNode.
727             RenderBlock* firstBlock = n->renderer()->containingBlock();
728 
729             // Get our containing block.
730             RenderBox* block = containingBlock();
731             localPoint.move(block->x() - firstBlock->x(), block->y() - firstBlock->y());
732         }
733 
734         result.setInnerNode(n);
735         if (!result.innerNonSharedNode())
736             result.setInnerNonSharedNode(n);
737         result.setLocalPoint(localPoint);
738     }
739 }
740 
dirtyLineBoxes(bool fullLayout)741 void RenderInline::dirtyLineBoxes(bool fullLayout)
742 {
743     if (fullLayout)
744         m_lineBoxes.deleteLineBoxes(renderArena());
745     else
746         m_lineBoxes.dirtyLineBoxes();
747 }
748 
createInlineFlowBox()749 InlineFlowBox* RenderInline::createInlineFlowBox()
750 {
751     return new (renderArena()) InlineFlowBox(this);
752 }
753 
createAndAppendInlineFlowBox()754 InlineFlowBox* RenderInline::createAndAppendInlineFlowBox()
755 {
756     InlineFlowBox* flowBox = createInlineFlowBox();
757     m_lineBoxes.appendLineBox(flowBox);
758     return flowBox;
759 }
760 
lineHeight(bool firstLine,bool) const761 int RenderInline::lineHeight(bool firstLine, bool /*isRootLineBox*/) const
762 {
763     if (firstLine && document()->usesFirstLineRules()) {
764         RenderStyle* s = style(firstLine);
765         if (s != style())
766             return s->computedLineHeight();
767     }
768 
769     if (m_lineHeight == -1)
770         m_lineHeight = style()->computedLineHeight();
771 
772     return m_lineHeight;
773 }
774 
verticalPositionFromCache(bool firstLine) const775 int RenderInline::verticalPositionFromCache(bool firstLine) const
776 {
777     if (firstLine) // We're only really a first-line style if the document actually uses first-line rules.
778         firstLine = document()->usesFirstLineRules();
779     int vpos = m_verticalPosition;
780     if (m_verticalPosition == PositionUndefined || firstLine) {
781         vpos = verticalPosition(firstLine);
782         if (!firstLine)
783             m_verticalPosition = vpos;
784     }
785     return vpos;
786 }
787 
relativePositionedInlineOffset(const RenderBox * child) const788 IntSize RenderInline::relativePositionedInlineOffset(const RenderBox* child) const
789 {
790     ASSERT(isRelPositioned());
791     if (!isRelPositioned())
792         return IntSize();
793 
794     // When we have an enclosing relpositioned inline, we need to add in the offset of the first line
795     // box from the rest of the content, but only in the cases where we know we're positioned
796     // relative to the inline itself.
797 
798     IntSize offset;
799     int sx;
800     int sy;
801     if (firstLineBox()) {
802         sx = firstLineBox()->x();
803         sy = firstLineBox()->y();
804     } else {
805         sx = layer()->staticX();
806         sy = layer()->staticY();
807     }
808 
809     if (!child->style()->hasStaticX())
810         offset.setWidth(sx);
811     // This is not terribly intuitive, but we have to match other browsers.  Despite being a block display type inside
812     // an inline, we still keep our x locked to the left of the relative positioned inline.  Arguably the correct
813     // behavior would be to go flush left to the block that contains the inline, but that isn't what other browsers
814     // do.
815     else if (!child->style()->isOriginalDisplayInlineType())
816         // Avoid adding in the left border/padding of the containing block twice.  Subtract it out.
817         offset.setWidth(sx - (child->containingBlock()->borderLeft() + child->containingBlock()->paddingLeft()));
818 
819     if (!child->style()->hasStaticY())
820         offset.setHeight(sy);
821 
822     return offset;
823 }
824 
imageChanged(WrappedImagePtr,const IntRect *)825 void RenderInline::imageChanged(WrappedImagePtr, const IntRect*)
826 {
827     if (!parent())
828         return;
829 
830     // FIXME: We can do better.
831     repaint();
832 }
833 
addFocusRingRects(GraphicsContext * graphicsContext,int tx,int ty)834 void RenderInline::addFocusRingRects(GraphicsContext* graphicsContext, int tx, int ty)
835 {
836     for (InlineRunBox* curr = firstLineBox(); curr; curr = curr->nextLineBox())
837         graphicsContext->addFocusRingRect(IntRect(tx + curr->x(), ty + curr->y(), curr->width(), curr->height()));
838 
839     for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) {
840         if (!curr->isText() && !curr->isListMarker()) {
841             FloatPoint pos(tx, ty);
842             // FIXME: This doesn't work correctly with transforms.
843             if (curr->hasLayer())
844                 pos = curr->localToAbsolute();
845             else if (curr->isBox())
846                 pos.move(toRenderBox(curr)->x(), toRenderBox(curr)->y());
847            curr->addFocusRingRects(graphicsContext, pos.x(), pos.y());
848         }
849     }
850 
851     if (continuation()) {
852         if (continuation()->isInline())
853             continuation()->addFocusRingRects(graphicsContext,
854                                               tx - containingBlock()->x() + continuation()->containingBlock()->x(),
855                                               ty - containingBlock()->y() + continuation()->containingBlock()->y());
856         else
857             continuation()->addFocusRingRects(graphicsContext,
858                                               tx - containingBlock()->x() + toRenderBox(continuation())->x(),
859                                               ty - containingBlock()->y() + toRenderBox(continuation())->y());
860     }
861 }
862 
paintOutline(GraphicsContext * graphicsContext,int tx,int ty)863 void RenderInline::paintOutline(GraphicsContext* graphicsContext, int tx, int ty)
864 {
865     if (!hasOutline())
866         return;
867 
868     if (style()->outlineStyleIsAuto() || hasOutlineAnnotation()) {
869         int ow = style()->outlineWidth();
870         Color oc = style()->outlineColor();
871         if (!oc.isValid())
872             oc = style()->color();
873 
874         graphicsContext->initFocusRing(ow, style()->outlineOffset());
875         addFocusRingRects(graphicsContext, tx, ty);
876         if (style()->outlineStyleIsAuto())
877             graphicsContext->drawFocusRing(oc);
878         else
879             addPDFURLRect(graphicsContext, graphicsContext->focusRingBoundingRect());
880         graphicsContext->clearFocusRing();
881     }
882 
883     if (style()->outlineStyleIsAuto() || style()->outlineStyle() == BNONE)
884         return;
885 
886     Vector<IntRect> rects;
887 
888     rects.append(IntRect());
889     for (InlineRunBox* curr = firstLineBox(); curr; curr = curr->nextLineBox())
890         rects.append(IntRect(curr->x(), curr->y(), curr->width(), curr->height()));
891 
892     rects.append(IntRect());
893 
894     for (unsigned i = 1; i < rects.size() - 1; i++)
895         paintOutlineForLine(graphicsContext, tx, ty, rects.at(i - 1), rects.at(i), rects.at(i + 1));
896 }
897 
paintOutlineForLine(GraphicsContext * graphicsContext,int tx,int ty,const IntRect & lastline,const IntRect & thisline,const IntRect & nextline)898 void RenderInline::paintOutlineForLine(GraphicsContext* graphicsContext, int tx, int ty,
899                                        const IntRect& lastline, const IntRect& thisline, const IntRect& nextline)
900 {
901     int ow = style()->outlineWidth();
902     EBorderStyle os = style()->outlineStyle();
903     Color oc = style()->outlineColor();
904     if (!oc.isValid())
905         oc = style()->color();
906 
907     int offset = style()->outlineOffset();
908 
909     int t = ty + thisline.y() - offset;
910     int l = tx + thisline.x() - offset;
911     int b = ty + thisline.bottom() + offset;
912     int r = tx + thisline.right() + offset;
913 
914     // left edge
915     drawLineForBoxSide(graphicsContext,
916                l - ow,
917                t - (lastline.isEmpty() || thisline.x() < lastline.x() || (lastline.right() - 1) <= thisline.x() ? ow : 0),
918                l,
919                b + (nextline.isEmpty() || thisline.x() <= nextline.x() || (nextline.right() - 1) <= thisline.x() ? ow : 0),
920                BSLeft,
921                oc, style()->color(), os,
922                (lastline.isEmpty() || thisline.x() < lastline.x() || (lastline.right() - 1) <= thisline.x() ? ow : -ow),
923                (nextline.isEmpty() || thisline.x() <= nextline.x() || (nextline.right() - 1) <= thisline.x() ? ow : -ow));
924 
925     // right edge
926     drawLineForBoxSide(graphicsContext,
927                r,
928                t - (lastline.isEmpty() || lastline.right() < thisline.right() || (thisline.right() - 1) <= lastline.x() ? ow : 0),
929                r + ow,
930                b + (nextline.isEmpty() || nextline.right() <= thisline.right() || (thisline.right() - 1) <= nextline.x() ? ow : 0),
931                BSRight,
932                oc, style()->color(), os,
933                (lastline.isEmpty() || lastline.right() < thisline.right() || (thisline.right() - 1) <= lastline.x() ? ow : -ow),
934                (nextline.isEmpty() || nextline.right() <= thisline.right() || (thisline.right() - 1) <= nextline.x() ? ow : -ow));
935     // upper edge
936     if (thisline.x() < lastline.x())
937         drawLineForBoxSide(graphicsContext,
938                    l - ow,
939                    t - ow,
940                    min(r+ow, (lastline.isEmpty() ? 1000000 : tx + lastline.x())),
941                    t ,
942                    BSTop, oc, style()->color(), os,
943                    ow,
944                    (!lastline.isEmpty() && tx + lastline.x() + 1 < r + ow) ? -ow : ow);
945 
946     if (lastline.right() < thisline.right())
947         drawLineForBoxSide(graphicsContext,
948                    max(lastline.isEmpty() ? -1000000 : tx + lastline.right(), l - ow),
949                    t - ow,
950                    r + ow,
951                    t ,
952                    BSTop, oc, style()->color(), os,
953                    (!lastline.isEmpty() && l - ow < tx + lastline.right()) ? -ow : ow,
954                    ow);
955 
956     // lower edge
957     if (thisline.x() < nextline.x())
958         drawLineForBoxSide(graphicsContext,
959                    l - ow,
960                    b,
961                    min(r + ow, !nextline.isEmpty() ? tx + nextline.x() + 1 : 1000000),
962                    b + ow,
963                    BSBottom, oc, style()->color(), os,
964                    ow,
965                    (!nextline.isEmpty() && tx + nextline.x() + 1 < r + ow) ? -ow : ow);
966 
967     if (nextline.right() < thisline.right())
968         drawLineForBoxSide(graphicsContext,
969                    max(!nextline.isEmpty() ? tx + nextline.right() : -1000000, l - ow),
970                    b,
971                    r + ow,
972                    b + ow,
973                    BSBottom, oc, style()->color(), os,
974                    (!nextline.isEmpty() && l - ow < tx + nextline.right()) ? -ow : ow,
975                    ow);
976 }
977 
978 #if ENABLE(DASHBOARD_SUPPORT)
addDashboardRegions(Vector<DashboardRegionValue> & regions)979 void RenderInline::addDashboardRegions(Vector<DashboardRegionValue>& regions)
980 {
981     // Convert the style regions to absolute coordinates.
982     if (style()->visibility() != VISIBLE)
983         return;
984 
985     const Vector<StyleDashboardRegion>& styleRegions = style()->dashboardRegions();
986     unsigned i, count = styleRegions.size();
987     for (i = 0; i < count; i++) {
988         StyleDashboardRegion styleRegion = styleRegions[i];
989 
990         IntRect linesBoundingBox = this->linesBoundingBox();
991         int w = linesBoundingBox.width();
992         int h = linesBoundingBox.height();
993 
994         DashboardRegionValue region;
995         region.label = styleRegion.label;
996         region.bounds = IntRect(linesBoundingBox.x() + styleRegion.offset.left().value(),
997                                 linesBoundingBox.y() + styleRegion.offset.top().value(),
998                                 w - styleRegion.offset.left().value() - styleRegion.offset.right().value(),
999                                 h - styleRegion.offset.top().value() - styleRegion.offset.bottom().value());
1000         region.type = styleRegion.type;
1001 
1002         RenderObject* container = containingBlock();
1003         if (!container)
1004             container = this;
1005 
1006         region.clip = region.bounds;
1007         container->computeAbsoluteRepaintRect(region.clip);
1008         if (region.clip.height() < 0) {
1009             region.clip.setHeight(0);
1010             region.clip.setWidth(0);
1011         }
1012 
1013         FloatPoint absPos = container->localToAbsolute();
1014         region.bounds.setX(absPos.x() + region.bounds.x());
1015         region.bounds.setY(absPos.y() + region.bounds.y());
1016 
1017         if (document()->frame()) {
1018             float pageScaleFactor = document()->frame()->page()->chrome()->scaleFactor();
1019             if (pageScaleFactor != 1.0f) {
1020                 region.bounds.scale(pageScaleFactor);
1021                 region.clip.scale(pageScaleFactor);
1022             }
1023         }
1024 
1025         regions.append(region);
1026     }
1027 }
1028 #endif
1029 
1030 } // namespace WebCore
1031