OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 2011 Adobe Systems Incorporated. All rights reserved. | 2 * Copyright (C) 2011 Adobe Systems Incorporated. All rights reserved. |
3 * | 3 * |
4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
5 * modification, are permitted provided that the following conditions | 5 * modification, are permitted provided that the following conditions |
6 * are met: | 6 * are met: |
7 * | 7 * |
8 * 1. Redistributions of source code must retain the above | 8 * 1. Redistributions of source code must retain the above |
9 * copyright notice, this list of conditions and the following | 9 * copyright notice, this list of conditions and the following |
10 * disclaimer. | 10 * disclaimer. |
(...skipping 19 matching lines...) Expand all Loading... |
30 #include "config.h" | 30 #include "config.h" |
31 | 31 |
32 #include "core/rendering/RenderFlowThread.h" | 32 #include "core/rendering/RenderFlowThread.h" |
33 | 33 |
34 #include "core/dom/Node.h" | 34 #include "core/dom/Node.h" |
35 #include "core/rendering/FlowThreadController.h" | 35 #include "core/rendering/FlowThreadController.h" |
36 #include "core/rendering/HitTestRequest.h" | 36 #include "core/rendering/HitTestRequest.h" |
37 #include "core/rendering/HitTestResult.h" | 37 #include "core/rendering/HitTestResult.h" |
38 #include "core/rendering/LayoutRectRecorder.h" | 38 #include "core/rendering/LayoutRectRecorder.h" |
39 #include "core/rendering/PaintInfo.h" | 39 #include "core/rendering/PaintInfo.h" |
40 #include "core/rendering/RenderBoxRegionInfo.h" | |
41 #include "core/rendering/RenderInline.h" | 40 #include "core/rendering/RenderInline.h" |
42 #include "core/rendering/RenderLayer.h" | 41 #include "core/rendering/RenderLayer.h" |
43 #include "core/rendering/RenderRegion.h" | 42 #include "core/rendering/RenderRegion.h" |
44 #include "core/rendering/RenderView.h" | 43 #include "core/rendering/RenderView.h" |
45 #include "platform/PODIntervalTree.h" | 44 #include "platform/PODIntervalTree.h" |
46 #include "platform/geometry/TransformState.h" | 45 #include "platform/geometry/TransformState.h" |
47 | 46 |
48 namespace WebCore { | 47 namespace WebCore { |
49 | 48 |
50 RenderFlowThread::RenderFlowThread() | 49 RenderFlowThread::RenderFlowThread() |
51 : RenderBlockFlow(0) | 50 : RenderBlockFlow(0) |
52 , m_previousRegionCount(0) | 51 , m_previousRegionCount(0) |
53 , m_autoLogicalHeightRegionsCount(0) | |
54 , m_regionsInvalidated(false) | 52 , m_regionsInvalidated(false) |
55 , m_regionsHaveUniformLogicalWidth(true) | |
56 , m_regionsHaveUniformLogicalHeight(true) | 53 , m_regionsHaveUniformLogicalHeight(true) |
57 , m_hasRegionsWithStyling(false) | |
58 , m_dispatchRegionLayoutUpdateEvent(false) | |
59 , m_dispatchRegionOversetChangeEvent(false) | |
60 , m_pageLogicalSizeChanged(false) | 54 , m_pageLogicalSizeChanged(false) |
61 , m_inConstrainedLayoutPhase(false) | |
62 , m_needsTwoPhasesLayout(false) | |
63 { | 55 { |
64 setFlowThreadState(InsideOutOfFlowThread); | 56 setFlowThreadState(InsideOutOfFlowThread); |
65 } | 57 } |
66 | 58 |
67 PassRefPtr<RenderStyle> RenderFlowThread::createFlowThreadStyle(RenderStyle* par
entStyle) | 59 PassRefPtr<RenderStyle> RenderFlowThread::createFlowThreadStyle(RenderStyle* par
entStyle) |
68 { | 60 { |
69 RefPtr<RenderStyle> newStyle(RenderStyle::create()); | 61 RefPtr<RenderStyle> newStyle(RenderStyle::create()); |
70 newStyle->inheritFrom(parentStyle); | 62 newStyle->inheritFrom(parentStyle); |
71 newStyle->setDisplay(BLOCK); | 63 newStyle->setDisplay(BLOCK); |
72 newStyle->setPosition(AbsolutePosition); | 64 newStyle->setPosition(AbsolutePosition); |
73 newStyle->setZIndex(0); | 65 newStyle->setZIndex(0); |
74 newStyle->setLeft(Length(0, Fixed)); | 66 newStyle->setLeft(Length(0, Fixed)); |
75 newStyle->setTop(Length(0, Fixed)); | 67 newStyle->setTop(Length(0, Fixed)); |
76 newStyle->setWidth(Length(100, Percent)); | 68 newStyle->setWidth(Length(100, Percent)); |
77 newStyle->setHeight(Length(100, Percent)); | 69 newStyle->setHeight(Length(100, Percent)); |
78 newStyle->font().update(0); | 70 newStyle->font().update(0); |
79 | 71 |
80 return newStyle.release(); | 72 return newStyle.release(); |
81 } | 73 } |
82 | 74 |
83 void RenderFlowThread::styleDidChange(StyleDifference diff, const RenderStyle* o
ldStyle) | |
84 { | |
85 RenderBlock::styleDidChange(diff, oldStyle); | |
86 | |
87 if (oldStyle && oldStyle->writingMode() != style()->writingMode()) | |
88 invalidateRegions(); | |
89 } | |
90 | |
91 void RenderFlowThread::removeFlowChildInfo(RenderObject* child) | |
92 { | |
93 if (child->isBox()) | |
94 removeRenderBoxRegionInfo(toRenderBox(child)); | |
95 clearRenderObjectCustomStyle(child); | |
96 } | |
97 | |
98 void RenderFlowThread::addRegionToThread(RenderRegion* renderRegion) | 75 void RenderFlowThread::addRegionToThread(RenderRegion* renderRegion) |
99 { | 76 { |
100 ASSERT(renderRegion); | 77 ASSERT(renderRegion); |
101 m_regionList.add(renderRegion); | 78 m_regionList.add(renderRegion); |
102 renderRegion->setIsValid(true); | 79 renderRegion->setIsValid(true); |
103 } | 80 } |
104 | 81 |
105 void RenderFlowThread::removeRegionFromThread(RenderRegion* renderRegion) | 82 void RenderFlowThread::removeRegionFromThread(RenderRegion* renderRegion) |
106 { | 83 { |
107 ASSERT(renderRegion); | 84 ASSERT(renderRegion); |
108 m_regionList.remove(renderRegion); | 85 m_regionList.remove(renderRegion); |
109 } | 86 } |
110 | 87 |
111 void RenderFlowThread::invalidateRegions() | 88 void RenderFlowThread::invalidateRegions() |
112 { | 89 { |
113 if (m_regionsInvalidated) { | 90 if (m_regionsInvalidated) { |
114 ASSERT(selfNeedsLayout()); | 91 ASSERT(selfNeedsLayout()); |
115 return; | 92 return; |
116 } | 93 } |
117 | 94 |
118 m_regionRangeMap.clear(); | 95 m_regionRangeMap.clear(); |
119 m_breakBeforeToRegionMap.clear(); | |
120 m_breakAfterToRegionMap.clear(); | |
121 setNeedsLayout(); | 96 setNeedsLayout(); |
122 | 97 |
123 m_regionsInvalidated = true; | 98 m_regionsInvalidated = true; |
124 } | 99 } |
125 | 100 |
126 class CurrentRenderFlowThreadDisabler { | 101 class CurrentRenderFlowThreadDisabler { |
127 WTF_MAKE_NONCOPYABLE(CurrentRenderFlowThreadDisabler); | 102 WTF_MAKE_NONCOPYABLE(CurrentRenderFlowThreadDisabler); |
128 public: | 103 public: |
129 CurrentRenderFlowThreadDisabler(RenderView* view) | 104 CurrentRenderFlowThreadDisabler(RenderView* view) |
130 : m_view(view) | 105 : m_view(view) |
(...skipping 10 matching lines...) Expand all Loading... |
141 } | 116 } |
142 private: | 117 private: |
143 RenderView* m_view; | 118 RenderView* m_view; |
144 RenderFlowThread* m_renderFlowThread; | 119 RenderFlowThread* m_renderFlowThread; |
145 }; | 120 }; |
146 | 121 |
147 void RenderFlowThread::validateRegions() | 122 void RenderFlowThread::validateRegions() |
148 { | 123 { |
149 if (m_regionsInvalidated) { | 124 if (m_regionsInvalidated) { |
150 m_regionsInvalidated = false; | 125 m_regionsInvalidated = false; |
151 m_regionsHaveUniformLogicalWidth = true; | |
152 m_regionsHaveUniformLogicalHeight = true; | 126 m_regionsHaveUniformLogicalHeight = true; |
153 | 127 |
154 if (hasRegions()) { | 128 if (hasRegions()) { |
155 LayoutUnit previousRegionLogicalWidth = 0; | 129 LayoutUnit previousRegionLogicalWidth = 0; |
156 LayoutUnit previousRegionLogicalHeight = 0; | 130 LayoutUnit previousRegionLogicalHeight = 0; |
157 bool firstRegionVisited = false; | 131 bool firstRegionVisited = false; |
158 | 132 |
159 for (RenderRegionList::iterator iter = m_regionList.begin(); iter !=
m_regionList.end(); ++iter) { | 133 for (RenderRegionList::iterator iter = m_regionList.begin(); iter !=
m_regionList.end(); ++iter) { |
160 RenderRegion* region = *iter; | 134 RenderRegion* region = *iter; |
161 ASSERT(!region->needsLayout() || region->isRenderRegionSet()); | |
162 | |
163 region->deleteAllRenderBoxRegionInfo(); | |
164 | |
165 // In the normal layout phase we need to initialize the computed
AutoHeight for auto-height regions. | |
166 // See initializeRegionsComputedAutoHeight for the explanation. | |
167 // Also, if we have auto-height regions we can't assume m_region
sHaveUniformLogicalHeight to be true in the first phase | |
168 // because the auto-height regions don't have their height compu
ted yet. | |
169 if (!inConstrainedLayoutPhase() && region->hasAutoLogicalHeight(
)) { | |
170 region->setComputedAutoHeight(region->maxPageLogicalHeight()
); | |
171 m_regionsHaveUniformLogicalHeight = false; | |
172 } | |
173 | |
174 LayoutUnit regionLogicalWidth = region->pageLogicalWidth(); | 135 LayoutUnit regionLogicalWidth = region->pageLogicalWidth(); |
175 LayoutUnit regionLogicalHeight = region->pageLogicalHeight(); | 136 LayoutUnit regionLogicalHeight = region->pageLogicalHeight(); |
176 | 137 |
177 if (!firstRegionVisited) { | 138 if (!firstRegionVisited) { |
178 firstRegionVisited = true; | 139 firstRegionVisited = true; |
179 } else { | 140 } else { |
180 if (m_regionsHaveUniformLogicalWidth && previousRegionLogica
lWidth != regionLogicalWidth) | |
181 m_regionsHaveUniformLogicalWidth = false; | |
182 if (m_regionsHaveUniformLogicalHeight && previousRegionLogic
alHeight != regionLogicalHeight) | 141 if (m_regionsHaveUniformLogicalHeight && previousRegionLogic
alHeight != regionLogicalHeight) |
183 m_regionsHaveUniformLogicalHeight = false; | 142 m_regionsHaveUniformLogicalHeight = false; |
184 } | 143 } |
185 | 144 |
186 previousRegionLogicalWidth = regionLogicalWidth; | 145 previousRegionLogicalWidth = regionLogicalWidth; |
187 } | 146 } |
188 } | 147 } |
189 } | 148 } |
190 | 149 |
191 updateLogicalWidth(); // Called to get the maximum logical width for the reg
ion. | 150 updateLogicalWidth(); // Called to get the maximum logical width for the reg
ion. |
192 updateRegionsFlowThreadPortionRect(); | 151 updateRegionsFlowThreadPortionRect(); |
193 } | 152 } |
194 | 153 |
195 void RenderFlowThread::layout() | 154 void RenderFlowThread::layout() |
196 { | 155 { |
197 LayoutRectRecorder recorder(*this); | 156 LayoutRectRecorder recorder(*this); |
198 m_pageLogicalSizeChanged = m_regionsInvalidated && everHadLayout(); | 157 m_pageLogicalSizeChanged = m_regionsInvalidated && everHadLayout(); |
199 | 158 |
200 // In case this is the second pass of the normal phase we need to update the
auto-height regions to their initial value. | |
201 // If the region chain was invalidated this will happen anyway. | |
202 if (!m_regionsInvalidated && !inConstrainedLayoutPhase()) | |
203 initializeRegionsComputedAutoHeight(); | |
204 | |
205 validateRegions(); | 159 validateRegions(); |
206 | 160 |
207 // This is the first phase of the layout and because we have auto-height reg
ions we'll need a second | |
208 // pass to update the flow with the computed auto-height regions. | |
209 m_needsTwoPhasesLayout = !inConstrainedLayoutPhase() && hasAutoLogicalHeight
Regions(); | |
210 | |
211 CurrentRenderFlowThreadMaintainer currentFlowThreadSetter(this); | 161 CurrentRenderFlowThreadMaintainer currentFlowThreadSetter(this); |
212 RenderBlockFlow::layout(); | 162 RenderBlockFlow::layout(); |
213 | 163 |
214 m_pageLogicalSizeChanged = false; | 164 m_pageLogicalSizeChanged = false; |
215 | 165 |
216 if (lastRegion()) | 166 if (lastRegion()) |
217 lastRegion()->expandToEncompassFlowThreadContentsIfNeeded(); | 167 lastRegion()->expandToEncompassFlowThreadContentsIfNeeded(); |
218 | |
219 if (shouldDispatchRegionLayoutUpdateEvent()) | |
220 dispatchRegionLayoutUpdateEvent(); | |
221 | |
222 if (shouldDispatchRegionOversetChangeEvent()) | |
223 dispatchRegionOversetChangeEvent(); | |
224 } | 168 } |
225 | 169 |
226 void RenderFlowThread::updateLogicalWidth() | 170 void RenderFlowThread::updateLogicalWidth() |
227 { | 171 { |
228 LayoutUnit logicalWidth = initialLogicalWidth(); | 172 setLogicalWidth(initialLogicalWidth()); |
229 for (RenderRegionList::iterator iter = m_regionList.begin(); iter != m_regio
nList.end(); ++iter) { | |
230 RenderRegion* region = *iter; | |
231 ASSERT(!region->needsLayout() || region->isRenderRegionSet()); | |
232 logicalWidth = max(region->pageLogicalWidth(), logicalWidth); | |
233 } | |
234 setLogicalWidth(logicalWidth); | |
235 | |
236 // If the regions have non-uniform logical widths, then insert inset informa
tion for the RenderFlowThread. | |
237 for (RenderRegionList::iterator iter = m_regionList.begin(); iter != m_regio
nList.end(); ++iter) { | |
238 RenderRegion* region = *iter; | |
239 LayoutUnit regionLogicalWidth = region->pageLogicalWidth(); | |
240 if (regionLogicalWidth != logicalWidth) { | |
241 LayoutUnit logicalLeft = style()->direction() == LTR ? LayoutUnit()
: logicalWidth - regionLogicalWidth; | |
242 region->setRenderBoxRegionInfo(this, logicalLeft, regionLogicalWidth
, false); | |
243 } | |
244 } | |
245 } | 173 } |
246 | 174 |
247 void RenderFlowThread::computeLogicalHeight(LayoutUnit, LayoutUnit logicalTop, L
ogicalExtentComputedValues& computedValues) const | 175 void RenderFlowThread::computeLogicalHeight(LayoutUnit, LayoutUnit logicalTop, L
ogicalExtentComputedValues& computedValues) const |
248 { | 176 { |
249 computedValues.m_position = logicalTop; | 177 computedValues.m_position = logicalTop; |
250 computedValues.m_extent = 0; | 178 computedValues.m_extent = 0; |
251 | 179 |
252 for (RenderRegionList::const_iterator iter = m_regionList.begin(); iter != m
_regionList.end(); ++iter) { | 180 for (RenderRegionList::const_iterator iter = m_regionList.begin(); iter != m
_regionList.end(); ++iter) { |
253 RenderRegion* region = *iter; | 181 RenderRegion* region = *iter; |
254 ASSERT(!region->needsLayout() || region->isRenderRegionSet()); | |
255 | |
256 computedValues.m_extent += region->logicalHeightOfAllFlowThreadContent()
; | 182 computedValues.m_extent += region->logicalHeightOfAllFlowThreadContent()
; |
257 } | 183 } |
258 } | 184 } |
259 | 185 |
260 LayoutRect RenderFlowThread::computeRegionClippingRect(const LayoutPoint& offset
, const LayoutRect& flowThreadPortionRect, const LayoutRect& flowThreadPortionOv
erflowRect) const | 186 LayoutRect RenderFlowThread::computeRegionClippingRect(const LayoutPoint& offset
, const LayoutRect& flowThreadPortionRect, const LayoutRect& flowThreadPortionOv
erflowRect) const |
261 { | 187 { |
262 LayoutRect regionClippingRect(offset + (flowThreadPortionOverflowRect.locati
on() - flowThreadPortionRect.location()), flowThreadPortionOverflowRect.size()); | 188 LayoutRect regionClippingRect(offset + (flowThreadPortionOverflowRect.locati
on() - flowThreadPortionRect.location()), flowThreadPortionOverflowRect.size()); |
263 if (style()->isFlippedBlocksWritingMode()) | 189 if (style()->isFlippedBlocksWritingMode()) |
264 regionClippingRect.move(flowThreadPortionRect.size() - flowThreadPortion
OverflowRect.size()); | 190 regionClippingRect.move(flowThreadPortionRect.size() - flowThreadPortion
OverflowRect.size()); |
265 return regionClippingRect; | 191 return regionClippingRect; |
266 } | 192 } |
267 | 193 |
268 void RenderFlowThread::paintFlowThreadPortionInRegion(PaintInfo& paintInfo, Rend
erRegion* region, const LayoutRect& flowThreadPortionRect, const LayoutRect& flo
wThreadPortionOverflowRect, const LayoutPoint& paintOffset) const | |
269 { | |
270 GraphicsContext* context = paintInfo.context; | |
271 if (!context) | |
272 return; | |
273 | |
274 // RenderFlowThread should start painting its content in a position that is
offset | |
275 // from the region rect's current position. The amount of offset is equal to
the location of | |
276 // the flow thread portion in the flow thread's local coordinates. | |
277 // Note that we have to pixel snap the location at which we're going to pain
t, since this is necessary | |
278 // to minimize the amount of incorrect snapping that would otherwise occur. | |
279 // If we tried to paint by applying a non-integral translation, then all the | |
280 // layout code that attempted to pixel snap would be incorrect. | |
281 IntPoint adjustedPaintOffset; | |
282 LayoutPoint portionLocation; | |
283 if (style()->isFlippedBlocksWritingMode()) { | |
284 LayoutRect flippedFlowThreadPortionRect(flowThreadPortionRect); | |
285 flipForWritingMode(flippedFlowThreadPortionRect); | |
286 portionLocation = flippedFlowThreadPortionRect.location(); | |
287 } else { | |
288 portionLocation = flowThreadPortionRect.location(); | |
289 } | |
290 adjustedPaintOffset = roundedIntPoint(paintOffset - portionLocation); | |
291 | |
292 // The clipping rect for the region is set up by assuming the flowThreadPort
ionRect is going to paint offset from adjustedPaintOffset. | |
293 // Remember that we pixel snapped and moved the paintOffset and stored the s
napped result in adjustedPaintOffset. Now we add back in | |
294 // the flowThreadPortionRect's location to get the spot where we expect the
portion to actually paint. This can be non-integral and | |
295 // that's ok. We then pixel snap the resulting clipping rect to account for
snapping that will occur when the flow thread paints. | |
296 IntRect regionClippingRect = pixelSnappedIntRect(computeRegionClippingRect(a
djustedPaintOffset + portionLocation, flowThreadPortionRect, flowThreadPortionOv
erflowRect)); | |
297 | |
298 PaintInfo info(paintInfo); | |
299 info.rect.intersect(regionClippingRect); | |
300 | |
301 if (!info.rect.isEmpty()) { | |
302 context->save(); | |
303 | |
304 context->clip(regionClippingRect); | |
305 | |
306 context->translate(adjustedPaintOffset.x(), adjustedPaintOffset.y()); | |
307 info.rect.moveBy(-adjustedPaintOffset); | |
308 | |
309 if (info.phase == PaintPhaseTextClip) | |
310 info.paintBehavior = PaintBehaviorForceBlackText; | |
311 | |
312 layer()->paint(context, info.rect, info.paintBehavior, 0, region, PaintL
ayerTemporaryClipRects); | |
313 | |
314 context->restore(); | |
315 } | |
316 } | |
317 | |
318 bool RenderFlowThread::nodeAtPoint(const HitTestRequest& request, HitTestResult&
result, const HitTestLocation& locationInContainer, const LayoutPoint& accumula
tedOffset, HitTestAction hitTestAction) | 194 bool RenderFlowThread::nodeAtPoint(const HitTestRequest& request, HitTestResult&
result, const HitTestLocation& locationInContainer, const LayoutPoint& accumula
tedOffset, HitTestAction hitTestAction) |
319 { | 195 { |
320 if (hitTestAction == HitTestBlockBackground) | 196 if (hitTestAction == HitTestBlockBackground) |
321 return false; | 197 return false; |
322 return RenderBlockFlow::nodeAtPoint(request, result, locationInContainer, ac
cumulatedOffset, hitTestAction); | 198 return RenderBlockFlow::nodeAtPoint(request, result, locationInContainer, ac
cumulatedOffset, hitTestAction); |
323 } | 199 } |
324 | 200 |
325 bool RenderFlowThread::hitTestFlowThreadPortionInRegion(RenderRegion* region, co
nst LayoutRect& flowThreadPortionRect, const LayoutRect& flowThreadPortionOverfl
owRect, const HitTestRequest& request, HitTestResult& result, const HitTestLocat
ion& locationInContainer, const LayoutPoint& accumulatedOffset) const | |
326 { | |
327 LayoutRect regionClippingRect = computeRegionClippingRect(accumulatedOffset,
flowThreadPortionRect, flowThreadPortionOverflowRect); | |
328 if (!regionClippingRect.contains(locationInContainer.point())) | |
329 return false; | |
330 | |
331 LayoutSize renderFlowThreadOffset; | |
332 if (style()->isFlippedBlocksWritingMode()) { | |
333 LayoutRect flippedFlowThreadPortionRect(flowThreadPortionRect); | |
334 flipForWritingMode(flippedFlowThreadPortionRect); | |
335 renderFlowThreadOffset = accumulatedOffset - flippedFlowThreadPortionRec
t.location(); | |
336 } else { | |
337 renderFlowThreadOffset = accumulatedOffset - flowThreadPortionRect.locat
ion(); | |
338 } | |
339 | |
340 // Always ignore clipping, since the RenderFlowThread has nothing to do with
the bounds of the FrameView. | |
341 HitTestRequest newRequest(request.type() | HitTestRequest::IgnoreClipping |
HitTestRequest::ConfusingAndOftenMisusedDisallowShadowContent); | |
342 | |
343 // Make a new temporary HitTestLocation in the new region. | |
344 HitTestLocation newHitTestLocation(locationInContainer, -renderFlowThreadOff
set, region); | |
345 | |
346 bool isPointInsideFlowThread = layer()->hitTest(newRequest, newHitTestLocati
on, result); | |
347 | |
348 // FIXME: Should we set result.m_localPoint back to the RenderRegion's coord
inate space or leave it in the RenderFlowThread's coordinate | |
349 // space? Right now it's staying in the RenderFlowThread's coordinate space,
which may end up being ok. We will know more when we get around to | |
350 // patching positionForPoint. | |
351 return isPointInsideFlowThread; | |
352 } | |
353 | |
354 bool RenderFlowThread::shouldRepaint(const LayoutRect& r) const | 201 bool RenderFlowThread::shouldRepaint(const LayoutRect& r) const |
355 { | 202 { |
356 if (view()->document().printing() || r.isEmpty()) | 203 if (view()->document().printing() || r.isEmpty()) |
357 return false; | 204 return false; |
358 | 205 |
359 return true; | 206 return true; |
360 } | 207 } |
361 | 208 |
362 void RenderFlowThread::repaintRectangleInRegions(const LayoutRect& repaintRect)
const | 209 void RenderFlowThread::repaintRectangleInRegions(const LayoutRect& repaintRect)
const |
363 { | 210 { |
(...skipping 21 matching lines...) Expand all Loading... |
385 autoGenerateRegionsToBlockOffset(offset); | 232 autoGenerateRegionsToBlockOffset(offset); |
386 | 233 |
387 if (offset <= 0) | 234 if (offset <= 0) |
388 return m_regionList.isEmpty() ? 0 : m_regionList.first(); | 235 return m_regionList.isEmpty() ? 0 : m_regionList.first(); |
389 | 236 |
390 RegionSearchAdapter adapter(offset); | 237 RegionSearchAdapter adapter(offset); |
391 m_regionIntervalTree.allOverlapsWithAdapter<RegionSearchAdapter>(adapter); | 238 m_regionIntervalTree.allOverlapsWithAdapter<RegionSearchAdapter>(adapter); |
392 | 239 |
393 // If no region was found, the offset is in the flow thread overflow. | 240 // If no region was found, the offset is in the flow thread overflow. |
394 // The last region will contain the offset if extendLastRegion is set or if
the last region is a set. | 241 // The last region will contain the offset if extendLastRegion is set or if
the last region is a set. |
395 if (!adapter.result() && !m_regionList.isEmpty() && (extendLastRegion || m_r
egionList.last()->isRenderRegionSet())) | 242 if (!adapter.result() && !m_regionList.isEmpty()) |
396 return m_regionList.last(); | 243 return m_regionList.last(); |
397 | 244 |
398 return adapter.result(); | 245 return adapter.result(); |
399 } | 246 } |
400 | 247 |
401 RenderRegion* RenderFlowThread::regionFromAbsolutePointAndBox(IntPoint absoluteP
oint, const RenderBox* flowedBox) | 248 RenderRegion* RenderFlowThread::regionFromAbsolutePointAndBox(IntPoint absoluteP
oint, const RenderBox* flowedBox) |
402 { | 249 { |
403 if (!flowedBox) | 250 if (!flowedBox) |
404 return 0; | 251 return 0; |
405 | 252 |
(...skipping 17 matching lines...) Expand all Loading... |
423 return 0; | 270 return 0; |
424 } | 271 } |
425 | 272 |
426 LayoutPoint RenderFlowThread::adjustedPositionRelativeToOffsetParent(const Rende
rBoxModelObject& boxModelObject, const LayoutPoint& startPoint) | 273 LayoutPoint RenderFlowThread::adjustedPositionRelativeToOffsetParent(const Rende
rBoxModelObject& boxModelObject, const LayoutPoint& startPoint) |
427 { | 274 { |
428 LayoutPoint referencePoint = startPoint; | 275 LayoutPoint referencePoint = startPoint; |
429 | 276 |
430 // FIXME: This needs to be adapted for different writing modes inside the fl
ow thread. | 277 // FIXME: This needs to be adapted for different writing modes inside the fl
ow thread. |
431 RenderRegion* startRegion = regionAtBlockOffset(referencePoint.y()); | 278 RenderRegion* startRegion = regionAtBlockOffset(referencePoint.y()); |
432 if (startRegion) { | 279 if (startRegion) { |
433 RenderBoxModelObject* startRegionBox = startRegion->isRenderNamedFlowFra
gment() ? toRenderBoxModelObject(startRegion->parent()) : startRegion; | |
434 // Take into account the offset coordinates of the region. | 280 // Take into account the offset coordinates of the region. |
435 RenderObject* currObject = startRegionBox; | 281 RenderObject* currObject = startRegion; |
436 RenderObject* currOffsetParentRenderer; | 282 RenderObject* currOffsetParentRenderer; |
437 Element* currOffsetParentElement; | 283 Element* currOffsetParentElement; |
438 while ((currOffsetParentElement = currObject->offsetParent()) && (currOf
fsetParentRenderer = currOffsetParentElement->renderer())) { | 284 while ((currOffsetParentElement = currObject->offsetParent()) && (currOf
fsetParentRenderer = currOffsetParentElement->renderer())) { |
439 if (currObject->isBoxModelObject()) | 285 if (currObject->isBoxModelObject()) |
440 referencePoint.move(toRenderBoxModelObject(currObject)->offsetLe
ft(), toRenderBoxModelObject(currObject)->offsetTop()); | 286 referencePoint.move(toRenderBoxModelObject(currObject)->offsetLe
ft(), toRenderBoxModelObject(currObject)->offsetTop()); |
441 | 287 |
442 // Since we're looking for the offset relative to the body, we must
also | 288 // Since we're looking for the offset relative to the body, we must
also |
443 // take into consideration the borders of the region's offsetParent. | 289 // take into consideration the borders of the region's offsetParent. |
444 if (currOffsetParentRenderer->isBox() && !currOffsetParentRenderer->
isBody()) | 290 if (currOffsetParentRenderer->isBox() && !currOffsetParentRenderer->
isBody()) |
445 referencePoint.move(toRenderBox(currOffsetParentRenderer)->borde
rLeft(), toRenderBox(currOffsetParentRenderer)->borderTop()); | 291 referencePoint.move(toRenderBox(currOffsetParentRenderer)->borde
rLeft(), toRenderBox(currOffsetParentRenderer)->borderTop()); |
446 | 292 |
447 currObject = currOffsetParentRenderer; | 293 currObject = currOffsetParentRenderer; |
448 } | 294 } |
449 | 295 |
450 // We need to check if any of this box's containing blocks start in a di
fferent region | 296 // We need to check if any of this box's containing blocks start in a di
fferent region |
451 // and if so, drop the object's top position (which was computed relativ
e to its containing block | 297 // and if so, drop the object's top position (which was computed relativ
e to its containing block |
452 // and is no longer valid) and recompute it using the region in which it
flows as reference. | 298 // and is no longer valid) and recompute it using the region in which it
flows as reference. |
453 bool wasComputedRelativeToOtherRegion = false; | 299 bool wasComputedRelativeToOtherRegion = false; |
454 const RenderBlock* objContainingBlock = boxModelObject.containingBlock()
; | 300 const RenderBlock* objContainingBlock = boxModelObject.containingBlock()
; |
455 while (objContainingBlock && !objContainingBlock->isRenderNamedFlowThrea
d()) { | 301 while (objContainingBlock) { |
456 // Check if this object is in a different region. | 302 // Check if this object is in a different region. |
457 RenderRegion* parentStartRegion = 0; | 303 RenderRegion* parentStartRegion = 0; |
458 RenderRegion* parentEndRegion = 0; | 304 RenderRegion* parentEndRegion = 0; |
459 getRegionRangeForBox(objContainingBlock, parentStartRegion, parentEn
dRegion); | 305 getRegionRangeForBox(objContainingBlock, parentStartRegion, parentEn
dRegion); |
460 if (parentStartRegion && parentStartRegion != startRegion) { | 306 if (parentStartRegion && parentStartRegion != startRegion) { |
461 wasComputedRelativeToOtherRegion = true; | 307 wasComputedRelativeToOtherRegion = true; |
462 break; | 308 break; |
463 } | 309 } |
464 objContainingBlock = objContainingBlock->containingBlock(); | 310 objContainingBlock = objContainingBlock->containingBlock(); |
465 } | 311 } |
466 | 312 |
467 if (wasComputedRelativeToOtherRegion) { | 313 if (wasComputedRelativeToOtherRegion) { |
468 if (boxModelObject.isBox()) { | |
469 // Use borderBoxRectInRegion to account for variations such as p
ercentage margins. | |
470 LayoutRect borderBoxRect = toRenderBox(&boxModelObject)->borderB
oxRectInRegion(startRegion, RenderBox::DoNotCacheRenderBoxRegionInfo); | |
471 referencePoint.move(borderBoxRect.location().x(), 0); | |
472 } | |
473 | |
474 // Get the logical top coordinate of the current object. | 314 // Get the logical top coordinate of the current object. |
475 LayoutUnit top = 0; | 315 LayoutUnit top = 0; |
476 if (boxModelObject.isRenderBlock()) { | 316 if (boxModelObject.isRenderBlock()) { |
477 top = toRenderBlock(&boxModelObject)->offsetFromLogicalTopOfFirs
tPage(); | 317 top = toRenderBlock(&boxModelObject)->offsetFromLogicalTopOfFirs
tPage(); |
478 } else { | 318 } else { |
479 if (boxModelObject.containingBlock()) | 319 if (boxModelObject.containingBlock()) |
480 top = boxModelObject.containingBlock()->offsetFromLogicalTop
OfFirstPage(); | 320 top = boxModelObject.containingBlock()->offsetFromLogicalTop
OfFirstPage(); |
481 | 321 |
482 if (boxModelObject.isBox()) | 322 if (boxModelObject.isBox()) |
483 top += toRenderBox(&boxModelObject)->topLeftLocation().y(); | 323 top += toRenderBox(&boxModelObject)->topLeftLocation().y(); |
484 else if (boxModelObject.isRenderInline()) | 324 else if (boxModelObject.isRenderInline()) |
485 top -= toRenderInline(&boxModelObject)->borderTop(); | 325 top -= toRenderInline(&boxModelObject)->borderTop(); |
486 } | 326 } |
487 | 327 |
488 // Get the logical top of the region this object starts in | 328 // Get the logical top of the region this object starts in |
489 // and compute the object's top, relative to the region's top. | 329 // and compute the object's top, relative to the region's top. |
490 LayoutUnit regionLogicalTop = startRegion->pageLogicalTopForOffset(t
op); | 330 LayoutUnit regionLogicalTop = startRegion->pageLogicalTopForOffset(t
op); |
491 LayoutUnit topRelativeToRegion = top - regionLogicalTop; | 331 LayoutUnit topRelativeToRegion = top - regionLogicalTop; |
492 referencePoint.setY(startRegionBox->offsetTop() + topRelativeToRegio
n); | 332 referencePoint.setY(startRegion->offsetTop() + topRelativeToRegion); |
493 | 333 |
494 // Since the top has been overriden, check if the | 334 // Since the top has been overriden, check if the |
495 // relative/sticky positioning must be reconsidered. | 335 // relative/sticky positioning must be reconsidered. |
496 if (boxModelObject.isRelPositioned()) | 336 if (boxModelObject.isRelPositioned()) |
497 referencePoint.move(0, boxModelObject.relativePositionOffset().h
eight()); | 337 referencePoint.move(0, boxModelObject.relativePositionOffset().h
eight()); |
498 else if (boxModelObject.isStickyPositioned()) | 338 else if (boxModelObject.isStickyPositioned()) |
499 referencePoint.move(0, boxModelObject.stickyPositionOffset().hei
ght()); | 339 referencePoint.move(0, boxModelObject.stickyPositionOffset().hei
ght()); |
500 } | 340 } |
501 | 341 |
502 // Since we're looking for the offset relative to the body, we must also | 342 // Since we're looking for the offset relative to the body, we must also |
503 // take into consideration the borders of the region. | 343 // take into consideration the borders of the region. |
504 referencePoint.move(startRegionBox->borderLeft(), startRegionBox->border
Top()); | 344 referencePoint.move(startRegion->borderLeft(), startRegion->borderTop())
; |
505 } | 345 } |
506 | 346 |
507 return referencePoint; | 347 return referencePoint; |
508 } | 348 } |
509 | 349 |
510 LayoutUnit RenderFlowThread::pageLogicalTopForOffset(LayoutUnit offset) | 350 LayoutUnit RenderFlowThread::pageLogicalTopForOffset(LayoutUnit offset) |
511 { | 351 { |
512 RenderRegion* region = regionAtBlockOffset(offset); | 352 RenderRegion* region = regionAtBlockOffset(offset); |
513 return region ? region->pageLogicalTopForOffset(offset) : LayoutUnit(); | 353 return region ? region->pageLogicalTopForOffset(offset) : LayoutUnit(); |
514 } | 354 } |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
564 return 0; | 404 return 0; |
565 | 405 |
566 LayoutRect flippedRegionRect(renderRegion->flowThreadPortionRect()); | 406 LayoutRect flippedRegionRect(renderRegion->flowThreadPortionRect()); |
567 flipForWritingMode(flippedRegionRect); | 407 flipForWritingMode(flippedRegionRect); |
568 | 408 |
569 transformState.move(renderRegion->contentBoxRect().location() - flippedRegio
nRect.location()); | 409 transformState.move(renderRegion->contentBoxRect().location() - flippedRegio
nRect.location()); |
570 | 410 |
571 return renderRegion; | 411 return renderRegion; |
572 } | 412 } |
573 | 413 |
574 void RenderFlowThread::removeRenderBoxRegionInfo(RenderBox* box) | |
575 { | |
576 if (!hasRegions()) | |
577 return; | |
578 | |
579 // If the region chain was invalidated the next layout will clear the box in
formation from all the regions. | |
580 if (m_regionsInvalidated) { | |
581 ASSERT(selfNeedsLayout()); | |
582 return; | |
583 } | |
584 | |
585 RenderRegion* startRegion; | |
586 RenderRegion* endRegion; | |
587 getRegionRangeForBox(box, startRegion, endRegion); | |
588 | |
589 for (RenderRegionList::iterator iter = m_regionList.find(startRegion); iter
!= m_regionList.end(); ++iter) { | |
590 RenderRegion* region = *iter; | |
591 region->removeRenderBoxRegionInfo(box); | |
592 if (region == endRegion) | |
593 break; | |
594 } | |
595 | |
596 #ifndef NDEBUG | |
597 // We have to make sure we did not leave any RenderBoxRegionInfo attached. | |
598 for (RenderRegionList::iterator iter = m_regionList.begin(); iter != m_regio
nList.end(); ++iter) { | |
599 RenderRegion* region = *iter; | |
600 ASSERT(!region->renderBoxRegionInfo(box)); | |
601 } | |
602 #endif | |
603 | |
604 m_regionRangeMap.remove(box); | |
605 } | |
606 | |
607 bool RenderFlowThread::logicalWidthChangedInRegionsForBlock(const RenderBlock* b
lock) | |
608 { | |
609 if (!hasRegions()) | |
610 return false; | |
611 | |
612 RenderRegion* startRegion; | |
613 RenderRegion* endRegion; | |
614 getRegionRangeForBox(block, startRegion, endRegion); | |
615 | |
616 // When the region chain is invalidated the box information is discarded so
we must assume the width has changed. | |
617 if (m_pageLogicalSizeChanged && !startRegion) | |
618 return true; | |
619 | |
620 // Not necessary for the flow thread, since we already computed the correct
info for it. | |
621 if (block == this) | |
622 return false; | |
623 | |
624 for (RenderRegionList::iterator iter = m_regionList.find(startRegion); iter
!= m_regionList.end(); ++iter) { | |
625 RenderRegion* region = *iter; | |
626 ASSERT(!region->needsLayout() || region->isRenderRegionSet()); | |
627 | |
628 OwnPtr<RenderBoxRegionInfo> oldInfo = region->takeRenderBoxRegionInfo(bl
ock); | |
629 if (!oldInfo) | |
630 continue; | |
631 | |
632 LayoutUnit oldLogicalWidth = oldInfo->logicalWidth(); | |
633 RenderBoxRegionInfo* newInfo = block->renderBoxRegionInfo(region); | |
634 if (!newInfo || newInfo->logicalWidth() != oldLogicalWidth) | |
635 return true; | |
636 | |
637 if (region == endRegion) | |
638 break; | |
639 } | |
640 | |
641 return false; | |
642 } | |
643 | |
644 LayoutUnit RenderFlowThread::contentLogicalWidthOfFirstRegion() const | |
645 { | |
646 RenderRegion* firstValidRegionInFlow = firstRegion(); | |
647 if (!firstValidRegionInFlow) | |
648 return 0; | |
649 return isHorizontalWritingMode() ? firstValidRegionInFlow->contentWidth() :
firstValidRegionInFlow->contentHeight(); | |
650 } | |
651 | |
652 LayoutUnit RenderFlowThread::contentLogicalHeightOfFirstRegion() const | |
653 { | |
654 RenderRegion* firstValidRegionInFlow = firstRegion(); | |
655 if (!firstValidRegionInFlow) | |
656 return 0; | |
657 return isHorizontalWritingMode() ? firstValidRegionInFlow->contentHeight() :
firstValidRegionInFlow->contentWidth(); | |
658 } | |
659 | |
660 LayoutUnit RenderFlowThread::contentLogicalLeftOfFirstRegion() const | |
661 { | |
662 RenderRegion* firstValidRegionInFlow = firstRegion(); | |
663 if (!firstValidRegionInFlow) | |
664 return 0; | |
665 return isHorizontalWritingMode() ? firstValidRegionInFlow->flowThreadPortion
Rect().x() : firstValidRegionInFlow->flowThreadPortionRect().y(); | |
666 } | |
667 | |
668 RenderRegion* RenderFlowThread::firstRegion() const | 414 RenderRegion* RenderFlowThread::firstRegion() const |
669 { | 415 { |
670 if (!hasValidRegionInfo()) | 416 if (!hasValidRegionInfo()) |
671 return 0; | 417 return 0; |
672 return m_regionList.first(); | 418 return m_regionList.first(); |
673 } | 419 } |
674 | 420 |
675 RenderRegion* RenderFlowThread::lastRegion() const | 421 RenderRegion* RenderFlowThread::lastRegion() const |
676 { | 422 { |
677 if (!hasValidRegionInfo()) | 423 if (!hasValidRegionInfo()) |
678 return 0; | 424 return 0; |
679 return m_regionList.last(); | 425 return m_regionList.last(); |
680 } | 426 } |
681 | 427 |
682 void RenderFlowThread::clearRenderObjectCustomStyle(const RenderObject* object, | |
683 const RenderRegion* oldStartRegion, const RenderRegion* oldEndRegion, | |
684 const RenderRegion* newStartRegion, const RenderRegion* newEndRegion) | |
685 { | |
686 // Clear the styles for the object in the regions. | |
687 // The styles are not cleared for the regions that are contained in both ran
ges. | |
688 bool insideOldRegionRange = false; | |
689 bool insideNewRegionRange = false; | |
690 for (RenderRegionList::iterator iter = m_regionList.begin(); iter != m_regio
nList.end(); ++iter) { | |
691 RenderRegion* region = *iter; | |
692 | |
693 if (oldStartRegion == region) | |
694 insideOldRegionRange = true; | |
695 if (newStartRegion == region) | |
696 insideNewRegionRange = true; | |
697 | |
698 if (!(insideOldRegionRange && insideNewRegionRange)) | |
699 region->clearObjectStyleInRegion(object); | |
700 | |
701 if (oldEndRegion == region) | |
702 insideOldRegionRange = false; | |
703 if (newEndRegion == region) | |
704 insideNewRegionRange = false; | |
705 } | |
706 } | |
707 | |
708 void RenderFlowThread::setRegionRangeForBox(const RenderBox* box, LayoutUnit off
setFromLogicalTopOfFirstPage) | 428 void RenderFlowThread::setRegionRangeForBox(const RenderBox* box, LayoutUnit off
setFromLogicalTopOfFirstPage) |
709 { | 429 { |
710 if (!hasRegions()) | 430 if (!hasRegions()) |
711 return; | 431 return; |
712 | 432 |
713 // FIXME: Not right for differing writing-modes. | 433 // FIXME: Not right for differing writing-modes. |
714 RenderRegion* startRegion = regionAtBlockOffset(offsetFromLogicalTopOfFirstP
age, true); | 434 RenderRegion* startRegion = regionAtBlockOffset(offsetFromLogicalTopOfFirstP
age, true); |
715 RenderRegion* endRegion = regionAtBlockOffset(offsetFromLogicalTopOfFirstPag
e + box->logicalHeight(), true); | 435 RenderRegion* endRegion = regionAtBlockOffset(offsetFromLogicalTopOfFirstPag
e + box->logicalHeight(), true); |
716 RenderRegionRangeMap::iterator it = m_regionRangeMap.find(box); | 436 RenderRegionRangeMap::iterator it = m_regionRangeMap.find(box); |
717 if (it == m_regionRangeMap.end()) { | 437 if (it == m_regionRangeMap.end()) { |
718 m_regionRangeMap.set(box, RenderRegionRange(startRegion, endRegion)); | 438 m_regionRangeMap.set(box, RenderRegionRange(startRegion, endRegion)); |
719 clearRenderObjectCustomStyle(box); | |
720 return; | 439 return; |
721 } | 440 } |
722 | 441 |
723 // If nothing changed, just bail. | 442 // If nothing changed, just bail. |
724 RenderRegionRange& range = it->value; | 443 RenderRegionRange& range = it->value; |
725 if (range.startRegion() == startRegion && range.endRegion() == endRegion) | 444 if (range.startRegion() == startRegion && range.endRegion() == endRegion) |
726 return; | 445 return; |
727 | 446 |
728 // Delete any info that we find before our new startRegion and after our new
endRegion. | |
729 for (RenderRegionList::iterator iter = m_regionList.begin(); iter != m_regio
nList.end(); ++iter) { | |
730 RenderRegion* region = *iter; | |
731 if (region == startRegion) { | |
732 iter = m_regionList.find(endRegion); | |
733 continue; | |
734 } | |
735 | |
736 region->removeRenderBoxRegionInfo(box); | |
737 | |
738 if (region == range.endRegion()) | |
739 break; | |
740 } | |
741 | |
742 clearRenderObjectCustomStyle(box, range.startRegion(), range.endRegion(), st
artRegion, endRegion); | |
743 range.setRange(startRegion, endRegion); | 447 range.setRange(startRegion, endRegion); |
744 } | 448 } |
745 | 449 |
746 void RenderFlowThread::getRegionRangeForBox(const RenderBox* box, RenderRegion*&
startRegion, RenderRegion*& endRegion) const | 450 void RenderFlowThread::getRegionRangeForBox(const RenderBox* box, RenderRegion*&
startRegion, RenderRegion*& endRegion) const |
747 { | 451 { |
748 startRegion = 0; | 452 startRegion = 0; |
749 endRegion = 0; | 453 endRegion = 0; |
750 RenderRegionRangeMap::const_iterator it = m_regionRangeMap.find(box); | 454 RenderRegionRangeMap::const_iterator it = m_regionRangeMap.find(box); |
751 if (it == m_regionRangeMap.end()) | 455 if (it == m_regionRangeMap.end()) |
752 return; | 456 return; |
(...skipping 19 matching lines...) Expand all Loading... |
772 const RenderRegion* currRegion = *it; | 476 const RenderRegion* currRegion = *it; |
773 if (targetRegion == currRegion) | 477 if (targetRegion == currRegion) |
774 return true; | 478 return true; |
775 if (currRegion == endRegion) | 479 if (currRegion == endRegion) |
776 break; | 480 break; |
777 } | 481 } |
778 | 482 |
779 return false; | 483 return false; |
780 } | 484 } |
781 | 485 |
782 // Check if the content is flown into at least a region with region styling rule
s. | 486 void RenderFlowThread::updateRegionsFlowThreadPortionRect() |
783 void RenderFlowThread::checkRegionsWithStyling() | |
784 { | 487 { |
785 bool hasRegionsWithStyling = false; | |
786 for (RenderRegionList::iterator iter = m_regionList.begin(); iter != m_regio
nList.end(); ++iter) { | |
787 RenderRegion* region = *iter; | |
788 if (region->hasCustomRegionStyle()) { | |
789 hasRegionsWithStyling = true; | |
790 break; | |
791 } | |
792 } | |
793 m_hasRegionsWithStyling = hasRegionsWithStyling; | |
794 } | |
795 | |
796 bool RenderFlowThread::objectInFlowRegion(const RenderObject* object, const Rend
erRegion* region) const | |
797 { | |
798 ASSERT(object); | |
799 ASSERT(region); | |
800 | |
801 RenderFlowThread* flowThread = object->flowThreadContainingBlock(); | |
802 if (flowThread != this) | |
803 return false; | |
804 if (!m_regionList.contains(const_cast<RenderRegion*>(region))) | |
805 return false; | |
806 | |
807 RenderBox* enclosingBox = object->enclosingBox(); | |
808 RenderRegion* enclosingBoxStartRegion = 0; | |
809 RenderRegion* enclosingBoxEndRegion = 0; | |
810 getRegionRangeForBox(enclosingBox, enclosingBoxStartRegion, enclosingBoxEndR
egion); | |
811 if (!regionInRange(region, enclosingBoxStartRegion, enclosingBoxEndRegion)) | |
812 return false; | |
813 | |
814 if (object->isBox()) | |
815 return true; | |
816 | |
817 LayoutRect objectABBRect = object->absoluteBoundingBoxRect(true); | |
818 if (!objectABBRect.width()) | |
819 objectABBRect.setWidth(1); | |
820 if (!objectABBRect.height()) | |
821 objectABBRect.setHeight(1); | |
822 if (objectABBRect.intersects(region->absoluteBoundingBoxRect(true))) | |
823 return true; | |
824 | |
825 if (region == lastRegion()) { | |
826 // If the object does not intersect any of the enclosing box regions | |
827 // then the object is in last region. | |
828 for (RenderRegionList::const_iterator it = m_regionList.find(enclosingBo
xStartRegion); it != m_regionList.end(); ++it) { | |
829 const RenderRegion* currRegion = *it; | |
830 if (currRegion == region) | |
831 break; | |
832 if (objectABBRect.intersects(currRegion->absoluteBoundingBoxRect(tru
e))) | |
833 return false; | |
834 } | |
835 return true; | |
836 } | |
837 | |
838 return false; | |
839 } | |
840 | |
841 #ifndef NDEBUG | |
842 bool RenderFlowThread::isAutoLogicalHeightRegionsCountConsistent() const | |
843 { | |
844 unsigned autoLogicalHeightRegions = 0; | |
845 for (RenderRegionList::const_iterator iter = m_regionList.begin(); iter != m
_regionList.end(); ++iter) { | |
846 const RenderRegion* region = *iter; | |
847 if (region->hasAutoLogicalHeight()) | |
848 autoLogicalHeightRegions++; | |
849 } | |
850 | |
851 return autoLogicalHeightRegions == m_autoLogicalHeightRegionsCount; | |
852 } | |
853 #endif | |
854 | |
855 // During the normal layout phase of the named flow the regions are initialized
with a height equal to their max-height. | |
856 // This way unforced breaks are automatically placed when a region is full and t
he content height/position correctly estimated. | |
857 // Also, the region where a forced break falls is exactly the region found at th
e forced break offset inside the flow content. | |
858 void RenderFlowThread::initializeRegionsComputedAutoHeight(RenderRegion* startRe
gion) | |
859 { | |
860 ASSERT(!inConstrainedLayoutPhase()); | |
861 if (!hasAutoLogicalHeightRegions()) | |
862 return; | |
863 | |
864 RenderRegionList::iterator regionIter = startRegion ? m_regionList.find(star
tRegion) : m_regionList.begin(); | |
865 for (; regionIter != m_regionList.end(); ++regionIter) { | |
866 RenderRegion* region = *regionIter; | |
867 if (region->hasAutoLogicalHeight()) | |
868 region->setComputedAutoHeight(region->maxPageLogicalHeight()); | |
869 } | |
870 } | |
871 | |
872 void RenderFlowThread::markAutoLogicalHeightRegionsForLayout() | |
873 { | |
874 ASSERT(hasAutoLogicalHeightRegions()); | |
875 | |
876 for (RenderRegionList::iterator iter = m_regionList.begin(); iter != m_regio
nList.end(); ++iter) { | |
877 RenderRegion* region = *iter; | |
878 if (!region->hasAutoLogicalHeight()) | |
879 continue; | |
880 | |
881 // FIXME: We need to find a way to avoid marking all the regions ancesto
rs for layout | |
882 // as we are already inside layout. | |
883 region->setNeedsLayout(); | |
884 } | |
885 } | |
886 | |
887 void RenderFlowThread::updateRegionsFlowThreadPortionRect(const RenderRegion* la
stRegionWithContent) | |
888 { | |
889 ASSERT(!lastRegionWithContent || (!inConstrainedLayoutPhase() && hasAutoLogi
calHeightRegions())); | |
890 LayoutUnit logicalHeight = 0; | 488 LayoutUnit logicalHeight = 0; |
891 bool emptyRegionsSegment = false; | |
892 // FIXME: Optimize not to clear the interval all the time. This implies manu
ally managing the tree nodes lifecycle. | 489 // FIXME: Optimize not to clear the interval all the time. This implies manu
ally managing the tree nodes lifecycle. |
893 m_regionIntervalTree.clear(); | 490 m_regionIntervalTree.clear(); |
894 m_regionIntervalTree.initIfNeeded(); | 491 m_regionIntervalTree.initIfNeeded(); |
895 for (RenderRegionList::iterator iter = m_regionList.begin(); iter != m_regio
nList.end(); ++iter) { | 492 for (RenderRegionList::iterator iter = m_regionList.begin(); iter != m_regio
nList.end(); ++iter) { |
896 RenderRegion* region = *iter; | 493 RenderRegion* region = *iter; |
897 | 494 |
898 // If we find an empty auto-height region, clear the computedAutoHeight
value. | |
899 if (emptyRegionsSegment && region->hasAutoLogicalHeight()) | |
900 region->clearComputedAutoHeight(); | |
901 | |
902 LayoutUnit regionLogicalWidth = region->pageLogicalWidth(); | 495 LayoutUnit regionLogicalWidth = region->pageLogicalWidth(); |
903 LayoutUnit regionLogicalHeight = std::min<LayoutUnit>(RenderFlowThread::
maxLogicalHeight() - logicalHeight, region->logicalHeightOfAllFlowThreadContent(
)); | 496 LayoutUnit regionLogicalHeight = std::min<LayoutUnit>(RenderFlowThread::
maxLogicalHeight() - logicalHeight, region->logicalHeightOfAllFlowThreadContent(
)); |
904 | 497 |
905 LayoutRect regionRect(style()->direction() == LTR ? LayoutUnit() : logic
alWidth() - regionLogicalWidth, logicalHeight, regionLogicalWidth, regionLogical
Height); | 498 LayoutRect regionRect(style()->direction() == LTR ? LayoutUnit() : logic
alWidth() - regionLogicalWidth, logicalHeight, regionLogicalWidth, regionLogical
Height); |
906 | 499 |
907 region->setFlowThreadPortionRect(isHorizontalWritingMode() ? regionRect
: regionRect.transposedRect()); | 500 region->setFlowThreadPortionRect(isHorizontalWritingMode() ? regionRect
: regionRect.transposedRect()); |
908 | 501 |
909 m_regionIntervalTree.add(RegionIntervalTree::createInterval(logicalHeigh
t, logicalHeight + regionLogicalHeight, region)); | 502 m_regionIntervalTree.add(RegionIntervalTree::createInterval(logicalHeigh
t, logicalHeight + regionLogicalHeight, region)); |
910 | 503 |
911 logicalHeight += regionLogicalHeight; | 504 logicalHeight += regionLogicalHeight; |
912 | |
913 // Once we find the last region with content the next regions are consid
ered empty. | |
914 if (lastRegionWithContent == region) | |
915 emptyRegionsSegment = true; | |
916 } | 505 } |
917 | |
918 ASSERT(!lastRegionWithContent || emptyRegionsSegment); | |
919 } | |
920 | |
921 // Even if we require the break to occur at offsetBreakInFlowThread, because reg
ions may have min/max-height values, | |
922 // it is possible that the break will occur at a different offset than the origi
nal one required. | |
923 // offsetBreakAdjustment measures the different between the requested break offs
et and the current break offset. | |
924 bool RenderFlowThread::addForcedRegionBreak(LayoutUnit offsetBreakInFlowThread,
RenderObject* breakChild, bool isBefore, LayoutUnit* offsetBreakAdjustment) | |
925 { | |
926 // We take breaks into account for height computation for auto logical heigh
t regions | |
927 // only in the layout phase in which we lay out the flows threads unconstrai
ned | |
928 // and we use the content breaks to determine the computedAutoHeight for | |
929 // auto logical height regions. | |
930 if (inConstrainedLayoutPhase()) | |
931 return false; | |
932 | |
933 // Breaks can come before or after some objects. We need to track these obje
cts, so that if we get | |
934 // multiple breaks for the same object (for example because of multiple layo
uts on the same object), | |
935 // we need to invalidate every other region after the old one and start comp
uting from fresh. | |
936 RenderObjectToRegionMap& mapToUse = isBefore ? m_breakBeforeToRegionMap : m_
breakAfterToRegionMap; | |
937 RenderObjectToRegionMap::iterator iter = mapToUse.find(breakChild); | |
938 if (iter != mapToUse.end()) { | |
939 RenderRegionList::iterator regionIter = m_regionList.find(iter->value); | |
940 ASSERT_WITH_SECURITY_IMPLICATION(regionIter != m_regionList.end()); | |
941 ASSERT((*regionIter)->hasAutoLogicalHeight()); | |
942 initializeRegionsComputedAutoHeight(*regionIter); | |
943 | |
944 // We need to update the regions flow thread portion rect because we are
going to process | |
945 // a break on these regions. | |
946 updateRegionsFlowThreadPortionRect(); | |
947 } | |
948 | |
949 // Simulate a region break at offsetBreakInFlowThread. If it points inside a
n auto logical height region, | |
950 // then it determines the region computed auto height. | |
951 RenderRegion* region = regionAtBlockOffset(offsetBreakInFlowThread); | |
952 if (!region) | |
953 return false; | |
954 | |
955 bool lastBreakAfterContent = breakChild == this; | |
956 bool hasComputedAutoHeight = false; | |
957 | |
958 LayoutUnit currentRegionOffsetInFlowThread = isHorizontalWritingMode() ? reg
ion->flowThreadPortionRect().y() : region->flowThreadPortionRect().x(); | |
959 LayoutUnit offsetBreakInCurrentRegion = offsetBreakInFlowThread - currentReg
ionOffsetInFlowThread; | |
960 | |
961 if (region->hasAutoLogicalHeight()) { | |
962 // A forced break can appear only in an auto-height region that didn't h
ave a forced break before. | |
963 // This ASSERT is a good-enough heuristic to verify the above condition. | |
964 ASSERT(region->maxPageLogicalHeight() == region->computedAutoHeight()); | |
965 | |
966 mapToUse.set(breakChild, region); | |
967 | |
968 hasComputedAutoHeight = true; | |
969 | |
970 // Compute the region height pretending that the offsetBreakInCurrentReg
ion is the logicalHeight for the auto-height region. | |
971 LayoutUnit regionComputedAutoHeight = region->constrainContentBoxLogical
HeightByMinMax(offsetBreakInCurrentRegion, -1); | |
972 | |
973 // The new height of this region needs to be smaller than the initial va
lue, the max height. A forced break is the only way to change the initial | |
974 // height of an auto-height region besides content ending. | |
975 ASSERT(regionComputedAutoHeight <= region->maxPageLogicalHeight()); | |
976 | |
977 region->setComputedAutoHeight(regionComputedAutoHeight); | |
978 | |
979 currentRegionOffsetInFlowThread += regionComputedAutoHeight; | |
980 } else { | |
981 currentRegionOffsetInFlowThread += isHorizontalWritingMode() ? region->f
lowThreadPortionRect().height() : region->flowThreadPortionRect().width(); | |
982 } | |
983 | |
984 // If the break was found inside an auto-height region its size changed so w
e need to recompute the flow thread portion rectangles. | |
985 // Also, if this is the last break after the content we need to clear the co
mputedAutoHeight value on the last empty regions. | |
986 if (hasAutoLogicalHeightRegions() && lastBreakAfterContent) | |
987 updateRegionsFlowThreadPortionRect(region); | |
988 else if (hasComputedAutoHeight) | |
989 updateRegionsFlowThreadPortionRect(); | |
990 | |
991 if (offsetBreakAdjustment) | |
992 *offsetBreakAdjustment = max<LayoutUnit>(0, currentRegionOffsetInFlowThr
ead - offsetBreakInFlowThread); | |
993 | |
994 return hasComputedAutoHeight; | |
995 } | |
996 | |
997 void RenderFlowThread::incrementAutoLogicalHeightRegions() | |
998 { | |
999 if (!m_autoLogicalHeightRegionsCount) | |
1000 view()->flowThreadController()->incrementFlowThreadsWithAutoLogicalHeigh
tRegions(); | |
1001 ++m_autoLogicalHeightRegionsCount; | |
1002 } | |
1003 | |
1004 void RenderFlowThread::decrementAutoLogicalHeightRegions() | |
1005 { | |
1006 ASSERT(m_autoLogicalHeightRegionsCount > 0); | |
1007 --m_autoLogicalHeightRegionsCount; | |
1008 if (!m_autoLogicalHeightRegionsCount) | |
1009 view()->flowThreadController()->decrementFlowThreadsWithAutoLogicalHeigh
tRegions(); | |
1010 } | 506 } |
1011 | 507 |
1012 void RenderFlowThread::collectLayerFragments(LayerFragments& layerFragments, con
st LayoutRect& layerBoundingBox, const LayoutRect& dirtyRect) | 508 void RenderFlowThread::collectLayerFragments(LayerFragments& layerFragments, con
st LayoutRect& layerBoundingBox, const LayoutRect& dirtyRect) |
1013 { | 509 { |
1014 ASSERT(!m_regionsInvalidated); | 510 ASSERT(!m_regionsInvalidated); |
1015 | 511 |
1016 for (RenderRegionList::const_iterator iter = m_regionList.begin(); iter != m
_regionList.end(); ++iter) { | 512 for (RenderRegionList::const_iterator iter = m_regionList.begin(); iter != m
_regionList.end(); ++iter) { |
1017 RenderRegion* region = *iter; | 513 RenderRegion* region = *iter; |
1018 region->collectLayerFragments(layerFragments, layerBoundingBox, dirtyRec
t); | 514 region->collectLayerFragments(layerFragments, layerBoundingBox, dirtyRec
t); |
1019 } | 515 } |
(...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1160 } | 656 } |
1161 | 657 |
1162 CurrentRenderFlowThreadMaintainer::CurrentRenderFlowThreadMaintainer(RenderFlowT
hread* renderFlowThread) | 658 CurrentRenderFlowThreadMaintainer::CurrentRenderFlowThreadMaintainer(RenderFlowT
hread* renderFlowThread) |
1163 : m_renderFlowThread(renderFlowThread) | 659 : m_renderFlowThread(renderFlowThread) |
1164 , m_previousRenderFlowThread(0) | 660 , m_previousRenderFlowThread(0) |
1165 { | 661 { |
1166 if (!m_renderFlowThread) | 662 if (!m_renderFlowThread) |
1167 return; | 663 return; |
1168 RenderView* view = m_renderFlowThread->view(); | 664 RenderView* view = m_renderFlowThread->view(); |
1169 m_previousRenderFlowThread = view->flowThreadController()->currentRenderFlow
Thread(); | 665 m_previousRenderFlowThread = view->flowThreadController()->currentRenderFlow
Thread(); |
1170 ASSERT(!m_previousRenderFlowThread || !renderFlowThread->isRenderNamedFlowTh
read()); | |
1171 view->flowThreadController()->setCurrentRenderFlowThread(m_renderFlowThread)
; | 666 view->flowThreadController()->setCurrentRenderFlowThread(m_renderFlowThread)
; |
1172 } | 667 } |
1173 | 668 |
1174 CurrentRenderFlowThreadMaintainer::~CurrentRenderFlowThreadMaintainer() | 669 CurrentRenderFlowThreadMaintainer::~CurrentRenderFlowThreadMaintainer() |
1175 { | 670 { |
1176 if (!m_renderFlowThread) | 671 if (!m_renderFlowThread) |
1177 return; | 672 return; |
1178 RenderView* view = m_renderFlowThread->view(); | 673 RenderView* view = m_renderFlowThread->view(); |
1179 ASSERT(view->flowThreadController()->currentRenderFlowThread() == m_renderFl
owThread); | 674 ASSERT(view->flowThreadController()->currentRenderFlowThread() == m_renderFl
owThread); |
1180 view->flowThreadController()->setCurrentRenderFlowThread(m_previousRenderFlo
wThread); | 675 view->flowThreadController()->setCurrentRenderFlowThread(m_previousRenderFlo
wThread); |
1181 } | 676 } |
1182 | 677 |
1183 | 678 |
1184 } // namespace WebCore | 679 } // namespace WebCore |
OLD | NEW |