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