| 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 16 matching lines...) Expand all Loading... |
| 27 * SUCH DAMAGE. | 27 * SUCH DAMAGE. |
| 28 */ | 28 */ |
| 29 | 29 |
| 30 #include "config.h" | 30 #include "config.h" |
| 31 #include "core/rendering/RenderRegion.h" | 31 #include "core/rendering/RenderRegion.h" |
| 32 | 32 |
| 33 #include "core/css/resolver/StyleResolver.h" | 33 #include "core/css/resolver/StyleResolver.h" |
| 34 #include "core/rendering/FlowThreadController.h" | 34 #include "core/rendering/FlowThreadController.h" |
| 35 #include "core/rendering/HitTestLocation.h" | 35 #include "core/rendering/HitTestLocation.h" |
| 36 #include "core/rendering/PaintInfo.h" | 36 #include "core/rendering/PaintInfo.h" |
| 37 #include "core/rendering/RenderBoxRegionInfo.h" | 37 #include "core/rendering/RenderFlowThread.h" |
| 38 #include "core/rendering/RenderNamedFlowThread.h" | |
| 39 #include "core/rendering/RenderView.h" | 38 #include "core/rendering/RenderView.h" |
| 40 | 39 |
| 41 using namespace std; | 40 using namespace std; |
| 42 | 41 |
| 43 namespace WebCore { | 42 namespace WebCore { |
| 44 | 43 |
| 45 RenderRegion::RenderRegion(Element* element, RenderFlowThread* flowThread) | 44 RenderRegion::RenderRegion(Element* element, RenderFlowThread* flowThread) |
| 46 : RenderBlockFlow(element) | 45 : RenderBlockFlow(element) |
| 47 , m_flowThread(flowThread) | 46 , m_flowThread(flowThread) |
| 48 , m_parentNamedFlowThread(0) | |
| 49 , m_computedAutoHeight(-1) | |
| 50 , m_isValid(false) | 47 , m_isValid(false) |
| 51 , m_hasCustomRegionStyle(false) | |
| 52 , m_hasAutoLogicalHeight(false) | |
| 53 { | 48 { |
| 54 } | 49 } |
| 55 | 50 |
| 56 LayoutUnit RenderRegion::pageLogicalWidth() const | 51 LayoutUnit RenderRegion::pageLogicalWidth() const |
| 57 { | 52 { |
| 58 ASSERT(m_flowThread); | 53 ASSERT(m_flowThread); |
| 59 return m_flowThread->isHorizontalWritingMode() ? contentWidth() : contentHei
ght(); | 54 return m_flowThread->isHorizontalWritingMode() ? contentWidth() : contentHei
ght(); |
| 60 } | 55 } |
| 61 | 56 |
| 62 LayoutUnit RenderRegion::pageLogicalHeight() const | 57 LayoutUnit RenderRegion::pageLogicalHeight() const |
| 63 { | 58 { |
| 64 ASSERT(m_flowThread); | 59 ASSERT(m_flowThread); |
| 65 if (hasComputedAutoHeight() && !m_flowThread->inConstrainedLayoutPhase()) { | |
| 66 ASSERT(hasAutoLogicalHeight()); | |
| 67 return computedAutoHeight(); | |
| 68 } | |
| 69 return m_flowThread->isHorizontalWritingMode() ? contentHeight() : contentWi
dth(); | 60 return m_flowThread->isHorizontalWritingMode() ? contentHeight() : contentWi
dth(); |
| 70 } | 61 } |
| 71 | 62 |
| 72 // This method returns the maximum page size of a region with auto-height. This
is the initial | |
| 73 // height value for auto-height regions in the first layout phase of the parent
named flow. | |
| 74 LayoutUnit RenderRegion::maxPageLogicalHeight() const | |
| 75 { | |
| 76 ASSERT(m_flowThread); | |
| 77 ASSERT(hasAutoLogicalHeight() && !m_flowThread->inConstrainedLayoutPhase()); | |
| 78 return style()->logicalMaxHeight().isUndefined() ? RenderFlowThread::maxLogi
calHeight() : computeReplacedLogicalHeightUsing(style()->logicalMaxHeight()); | |
| 79 } | |
| 80 | |
| 81 LayoutUnit RenderRegion::logicalHeightOfAllFlowThreadContent() const | 63 LayoutUnit RenderRegion::logicalHeightOfAllFlowThreadContent() const |
| 82 { | 64 { |
| 83 ASSERT(m_flowThread); | 65 ASSERT(m_flowThread); |
| 84 if (hasComputedAutoHeight() && !m_flowThread->inConstrainedLayoutPhase()) { | |
| 85 ASSERT(hasAutoLogicalHeight()); | |
| 86 return computedAutoHeight(); | |
| 87 } | |
| 88 return m_flowThread->isHorizontalWritingMode() ? contentHeight() : contentWi
dth(); | 66 return m_flowThread->isHorizontalWritingMode() ? contentHeight() : contentWi
dth(); |
| 89 } | 67 } |
| 90 | 68 |
| 91 LayoutRect RenderRegion::flowThreadPortionOverflowRect() const | 69 LayoutRect RenderRegion::flowThreadPortionOverflowRect() const |
| 92 { | 70 { |
| 93 return overflowRectForFlowThreadPortion(flowThreadPortionRect(), isFirstRegi
on(), isLastRegion()); | 71 return overflowRectForFlowThreadPortion(flowThreadPortionRect(), isFirstRegi
on(), isLastRegion()); |
| 94 } | 72 } |
| 95 | 73 |
| 96 LayoutRect RenderRegion::overflowRectForFlowThreadPortion(const LayoutRect& flow
ThreadPortionRect, bool isFirstPortion, bool isLastPortion) const | 74 LayoutRect RenderRegion::overflowRectForFlowThreadPortion(const LayoutRect& flow
ThreadPortionRect, bool isFirstPortion, bool isLastPortion) const |
| 97 { | 75 { |
| 98 ASSERT(isValid()); | 76 ASSERT(isValid()); |
| 99 | 77 |
| 100 bool isLastRegionWithRegionFragmentBreak = (isLastPortion && (style()->regio
nFragment() == BreakRegionFragment)); | 78 if (hasOverflowClip()) |
| 101 if (hasOverflowClip() || isLastRegionWithRegionFragmentBreak) | |
| 102 return flowThreadPortionRect; | 79 return flowThreadPortionRect; |
| 103 | 80 |
| 104 LayoutRect flowThreadOverflow = m_flowThread->visualOverflowRect(); | 81 LayoutRect flowThreadOverflow = m_flowThread->visualOverflowRect(); |
| 105 | 82 |
| 106 // Only clip along the flow thread axis. | 83 // Only clip along the flow thread axis. |
| 107 LayoutUnit outlineSize = maximalOutlineSize(PaintPhaseOutline); | 84 LayoutUnit outlineSize = maximalOutlineSize(PaintPhaseOutline); |
| 108 LayoutRect clipRect; | 85 LayoutRect clipRect; |
| 109 bool shouldApplyClip = !style()->isOverflowVisible(); | 86 bool shouldApplyClip = !style()->isOverflowVisible(); |
| 110 if (m_flowThread->isHorizontalWritingMode()) { | 87 if (m_flowThread->isHorizontalWritingMode()) { |
| 111 LayoutUnit minY = isFirstPortion ? (flowThreadOverflow.y() - outlineSize
) : flowThreadPortionRect.y(); | 88 LayoutUnit minY = isFirstPortion ? (flowThreadOverflow.y() - outlineSize
) : flowThreadPortionRect.y(); |
| 112 LayoutUnit maxY = isLastPortion ? max(flowThreadPortionRect.maxY(), flow
ThreadOverflow.maxY()) + outlineSize : flowThreadPortionRect.maxY(); | 89 LayoutUnit maxY = isLastPortion ? max(flowThreadPortionRect.maxY(), flow
ThreadOverflow.maxY()) + outlineSize : flowThreadPortionRect.maxY(); |
| 113 LayoutUnit minX = shouldApplyClip ? flowThreadPortionRect.x() : min(flow
ThreadPortionRect.x(), flowThreadOverflow.x() - outlineSize); | 90 LayoutUnit minX = shouldApplyClip ? flowThreadPortionRect.x() : min(flow
ThreadPortionRect.x(), flowThreadOverflow.x() - outlineSize); |
| 114 LayoutUnit maxX = shouldApplyClip ? flowThreadPortionRect.maxX() : max(f
lowThreadPortionRect.maxX(), (flowThreadOverflow.maxX() + outlineSize)); | 91 LayoutUnit maxX = shouldApplyClip ? flowThreadPortionRect.maxX() : max(f
lowThreadPortionRect.maxX(), (flowThreadOverflow.maxX() + outlineSize)); |
| 115 clipRect = LayoutRect(minX, minY, maxX - minX, maxY - minY); | 92 clipRect = LayoutRect(minX, minY, maxX - minX, maxY - minY); |
| 116 } else { | 93 } else { |
| 117 LayoutUnit minX = isFirstPortion ? (flowThreadOverflow.x() - outlineSize
) : flowThreadPortionRect.x(); | 94 LayoutUnit minX = isFirstPortion ? (flowThreadOverflow.x() - outlineSize
) : flowThreadPortionRect.x(); |
| 118 LayoutUnit maxX = isLastPortion ? max(flowThreadPortionRect.maxX(), flow
ThreadOverflow.maxX()) + outlineSize : flowThreadPortionRect.maxX(); | 95 LayoutUnit maxX = isLastPortion ? max(flowThreadPortionRect.maxX(), flow
ThreadOverflow.maxX()) + outlineSize : flowThreadPortionRect.maxX(); |
| 119 LayoutUnit minY = shouldApplyClip ? flowThreadPortionRect.y() : min(flow
ThreadPortionRect.y(), (flowThreadOverflow.y() - outlineSize)); | 96 LayoutUnit minY = shouldApplyClip ? flowThreadPortionRect.y() : min(flow
ThreadPortionRect.y(), (flowThreadOverflow.y() - outlineSize)); |
| 120 LayoutUnit maxY = shouldApplyClip ? flowThreadPortionRect.maxY() : max(f
lowThreadPortionRect.y(), (flowThreadOverflow.maxY() + outlineSize)); | 97 LayoutUnit maxY = shouldApplyClip ? flowThreadPortionRect.maxY() : max(f
lowThreadPortionRect.y(), (flowThreadOverflow.maxY() + outlineSize)); |
| 121 clipRect = LayoutRect(minX, minY, maxX - minX, maxY - minY); | 98 clipRect = LayoutRect(minX, minY, maxX - minX, maxY - minY); |
| 122 } | 99 } |
| 123 | 100 |
| 124 return clipRect; | 101 return clipRect; |
| 125 } | 102 } |
| 126 | 103 |
| 127 RegionOversetState RenderRegion::regionOversetState() const | |
| 128 { | |
| 129 if (isValid() && element()) | |
| 130 return element()->regionOversetState(); | |
| 131 | |
| 132 return RegionUndefined; | |
| 133 } | |
| 134 | |
| 135 void RenderRegion::setRegionOversetState(RegionOversetState state) | |
| 136 { | |
| 137 if (element()) | |
| 138 element()->setRegionOversetState(state); | |
| 139 } | |
| 140 | |
| 141 Element* RenderRegion::element() const | |
| 142 { | |
| 143 ASSERT(nodeForRegion() && nodeForRegion()->isElementNode()); | |
| 144 return toElement(nodeForRegion()); | |
| 145 } | |
| 146 | |
| 147 LayoutUnit RenderRegion::pageLogicalTopForOffset(LayoutUnit /* offset */) const | 104 LayoutUnit RenderRegion::pageLogicalTopForOffset(LayoutUnit /* offset */) const |
| 148 { | 105 { |
| 149 return flowThread()->isHorizontalWritingMode() ? flowThreadPortionRect().y()
: flowThreadPortionRect().x(); | 106 return flowThread()->isHorizontalWritingMode() ? flowThreadPortionRect().y()
: flowThreadPortionRect().x(); |
| 150 } | 107 } |
| 151 | 108 |
| 152 bool RenderRegion::isFirstRegion() const | 109 bool RenderRegion::isFirstRegion() const |
| 153 { | 110 { |
| 154 ASSERT(isValid()); | 111 ASSERT(isValid()); |
| 155 | 112 |
| 156 return m_flowThread->firstRegion() == this; | 113 return m_flowThread->firstRegion() == this; |
| 157 } | 114 } |
| 158 | 115 |
| 159 bool RenderRegion::isLastRegion() const | 116 bool RenderRegion::isLastRegion() const |
| 160 { | 117 { |
| 161 ASSERT(isValid()); | 118 ASSERT(isValid()); |
| 162 | 119 |
| 163 return m_flowThread->lastRegion() == this; | 120 return m_flowThread->lastRegion() == this; |
| 164 } | 121 } |
| 165 | 122 |
| 166 static bool shouldPaintRegionContentsInPhase(PaintPhase phase) | |
| 167 { | |
| 168 return phase == PaintPhaseForeground | |
| 169 || phase == PaintPhaseSelection | |
| 170 || phase == PaintPhaseTextClip; | |
| 171 } | |
| 172 | |
| 173 void RenderRegion::paintObject(PaintInfo& paintInfo, const LayoutPoint& paintOff
set) | |
| 174 { | |
| 175 if (style()->visibility() != VISIBLE) | |
| 176 return; | |
| 177 | |
| 178 RenderBlock::paintObject(paintInfo, paintOffset); | |
| 179 | |
| 180 if (!isValid()) | |
| 181 return; | |
| 182 | |
| 183 // Delegate painting of content in region to RenderFlowThread. | |
| 184 // RenderFlowThread is a self painting layer (being a positioned object) who
is painting its children, the collected objects. | |
| 185 // Since we do not want to paint the flow thread content multiple times (for
each painting phase of the region object), | |
| 186 // we allow the flow thread painting only in certain phases. | |
| 187 if (!shouldPaintRegionContentsInPhase(paintInfo.phase)) | |
| 188 return; | |
| 189 | |
| 190 setRegionObjectsRegionStyle(); | |
| 191 m_flowThread->paintFlowThreadPortionInRegion(paintInfo, this, flowThreadPort
ionRect(), flowThreadPortionOverflowRect(), LayoutPoint(paintOffset.x() + border
Left() + paddingLeft(), paintOffset.y() + borderTop() + paddingTop())); | |
| 192 restoreRegionObjectsOriginalStyle(); | |
| 193 } | |
| 194 | |
| 195 // Hit Testing | |
| 196 bool RenderRegion::hitTestFlowThreadContents(const HitTestRequest& request, HitT
estResult& result, const HitTestLocation& locationInContainer, const LayoutPoint
& accumulatedOffset, HitTestAction action) | |
| 197 { | |
| 198 if (!isValid() || action != HitTestForeground) | |
| 199 return false; | |
| 200 | |
| 201 LayoutRect boundsRect = borderBoxRectInRegion(locationInContainer.region()); | |
| 202 boundsRect.moveBy(accumulatedOffset); | |
| 203 if (visibleToHitTesting() && locationInContainer.intersects(boundsRect)) { | |
| 204 if (m_flowThread->hitTestFlowThreadPortionInRegion(this, flowThreadPorti
onRect(), flowThreadPortionOverflowRect(), request, result, | |
| 205 locationInContainer, LayoutPoint(accumulatedOffset.x() + borderLeft(
) + paddingLeft(), accumulatedOffset.y() + borderTop() + paddingTop()))) | |
| 206 return true; | |
| 207 } | |
| 208 | |
| 209 return false; | |
| 210 } | |
| 211 | |
| 212 void RenderRegion::checkRegionStyle() | |
| 213 { | |
| 214 ASSERT(m_flowThread); | |
| 215 bool customRegionStyle = false; | |
| 216 | |
| 217 // FIXME: Region styling doesn't work for pseudo elements. | |
| 218 if (isElementBasedRegion()) | |
| 219 customRegionStyle = view()->document().ensureStyleResolver().checkRegion
Style(this->element()); | |
| 220 | |
| 221 setHasCustomRegionStyle(customRegionStyle); | |
| 222 m_flowThread->checkRegionsWithStyling(); | |
| 223 } | |
| 224 | |
| 225 void RenderRegion::incrementAutoLogicalHeightCount() | |
| 226 { | |
| 227 ASSERT(isValid()); | |
| 228 ASSERT(m_hasAutoLogicalHeight); | |
| 229 | |
| 230 m_flowThread->incrementAutoLogicalHeightRegions(); | |
| 231 } | |
| 232 | |
| 233 void RenderRegion::decrementAutoLogicalHeightCount() | |
| 234 { | |
| 235 ASSERT(isValid()); | |
| 236 | |
| 237 m_flowThread->decrementAutoLogicalHeightRegions(); | |
| 238 } | |
| 239 | |
| 240 void RenderRegion::updateRegionHasAutoLogicalHeightFlag() | |
| 241 { | |
| 242 ASSERT(m_flowThread); | |
| 243 | |
| 244 if (!isValid()) | |
| 245 return; | |
| 246 | |
| 247 bool didHaveAutoLogicalHeight = m_hasAutoLogicalHeight; | |
| 248 m_hasAutoLogicalHeight = shouldHaveAutoLogicalHeight(); | |
| 249 if (m_hasAutoLogicalHeight != didHaveAutoLogicalHeight) { | |
| 250 if (m_hasAutoLogicalHeight) { | |
| 251 incrementAutoLogicalHeightCount(); | |
| 252 } else { | |
| 253 clearComputedAutoHeight(); | |
| 254 decrementAutoLogicalHeightCount(); | |
| 255 } | |
| 256 } | |
| 257 } | |
| 258 | |
| 259 bool RenderRegion::shouldHaveAutoLogicalHeight() const | |
| 260 { | |
| 261 bool hasSpecifiedEndpointsForHeight = style()->logicalTop().isSpecified() &&
style()->logicalBottom().isSpecified(); | |
| 262 bool hasAnchoredEndpointsForHeight = isOutOfFlowPositioned() && hasSpecified
EndpointsForHeight; | |
| 263 bool hasAutoHeightStyle = style()->logicalHeight().isAuto() || style()->logi
calHeight().isFitContent() | |
| 264 || style()->logicalHeight().isMaxContent() || style()->logicalHeight().i
sMinContent(); | |
| 265 return hasAutoHeightStyle && !hasAnchoredEndpointsForHeight; | |
| 266 } | |
| 267 | |
| 268 void RenderRegion::styleDidChange(StyleDifference diff, const RenderStyle* oldSt
yle) | |
| 269 { | |
| 270 RenderBlock::styleDidChange(diff, oldStyle); | |
| 271 | |
| 272 // If the region is not attached to any thread, there is no need to check | |
| 273 // whether the region has region styling since no content will be displayed | |
| 274 // into the region. | |
| 275 if (!m_flowThread) { | |
| 276 setHasCustomRegionStyle(false); | |
| 277 return; | |
| 278 } | |
| 279 | |
| 280 checkRegionStyle(); | |
| 281 updateRegionHasAutoLogicalHeightFlag(); | |
| 282 | |
| 283 if (oldStyle && oldStyle->writingMode() != style()->writingMode()) | |
| 284 m_flowThread->regionChangedWritingMode(this); | |
| 285 } | |
| 286 | |
| 287 void RenderRegion::layoutBlock(bool relayoutChildren) | 123 void RenderRegion::layoutBlock(bool relayoutChildren) |
| 288 { | 124 { |
| 289 RenderBlockFlow::layoutBlock(relayoutChildren); | 125 RenderBlockFlow::layoutBlock(relayoutChildren); |
| 290 | 126 |
| 291 if (isValid()) { | |
| 292 LayoutRect oldRegionRect(flowThreadPortionRect()); | |
| 293 if (!isHorizontalWritingMode()) | |
| 294 oldRegionRect = oldRegionRect.transposedRect(); | |
| 295 | |
| 296 if (hasAutoLogicalHeight() && !m_flowThread->inConstrainedLayoutPhase())
{ | |
| 297 m_flowThread->invalidateRegions(); | |
| 298 clearComputedAutoHeight(); | |
| 299 return; | |
| 300 } | |
| 301 | |
| 302 if (!isRenderRegionSet() && (oldRegionRect.width() != pageLogicalWidth()
|| oldRegionRect.height() != pageLogicalHeight())) { | |
| 303 // This can happen even if we are in the inConstrainedLayoutPhase an
d it will trigger a pathological layout of the flow thread. | |
| 304 m_flowThread->invalidateRegions(); | |
| 305 } | |
| 306 } | |
| 307 | |
| 308 // FIXME: We need to find a way to set up overflow properly. Our flow thread
hasn't gotten a layout | 127 // FIXME: We need to find a way to set up overflow properly. Our flow thread
hasn't gotten a layout |
| 309 // yet, so we can't look to it for correct information. It's possible we cou
ld wait until after the RenderFlowThread | 128 // yet, so we can't look to it for correct information. It's possible we cou
ld wait until after the RenderFlowThread |
| 310 // gets a layout, and then try to propagate overflow information back to the
region, and then mark for a second layout. | 129 // gets a layout, and then try to propagate overflow information back to the
region, and then mark for a second layout. |
| 311 // That second layout would then be able to use the information from the Ren
derFlowThread to set up overflow. | 130 // That second layout would then be able to use the information from the Ren
derFlowThread to set up overflow. |
| 312 // | 131 // |
| 313 // The big problem though is that overflow needs to be region-specific. We c
an't simply use the RenderFlowThread's global | 132 // The big problem though is that overflow needs to be region-specific. We c
an't simply use the RenderFlowThread's global |
| 314 // overflow values, since then we'd always think any narrow region had huge
overflow (all the way to the width of the | 133 // overflow values, since then we'd always think any narrow region had huge
overflow (all the way to the width of the |
| 315 // RenderFlowThread itself). | 134 // RenderFlowThread itself). |
| 316 // | |
| 317 // We'll need to expand RenderBoxRegionInfo to also hold left and right over
flow values. | |
| 318 } | 135 } |
| 319 | 136 |
| 320 void RenderRegion::repaintFlowThreadContent(const LayoutRect& repaintRect) const | 137 void RenderRegion::repaintFlowThreadContent(const LayoutRect& repaintRect) const |
| 321 { | 138 { |
| 322 repaintFlowThreadContentRectangle(repaintRect, flowThreadPortionRect(), flow
ThreadPortionOverflowRect(), contentBoxRect().location()); | 139 repaintFlowThreadContentRectangle(repaintRect, flowThreadPortionRect(), flow
ThreadPortionOverflowRect(), contentBoxRect().location()); |
| 323 } | 140 } |
| 324 | 141 |
| 325 void RenderRegion::repaintFlowThreadContentRectangle(const LayoutRect& repaintRe
ct, const LayoutRect& flowThreadPortionRect, const LayoutRect& flowThreadPortion
OverflowRect, const LayoutPoint& regionLocation) const | 142 void RenderRegion::repaintFlowThreadContentRectangle(const LayoutRect& repaintRe
ct, const LayoutRect& flowThreadPortionRect, const LayoutRect& flowThreadPortion
OverflowRect, const LayoutPoint& regionLocation) const |
| 326 { | 143 { |
| 327 ASSERT(isValid()); | 144 ASSERT(isValid()); |
| (...skipping 12 matching lines...) Expand all Loading... |
| 340 // Put the region rect into the region's physical coordinate space. | 157 // Put the region rect into the region's physical coordinate space. |
| 341 clippedRect.setLocation(regionLocation + (clippedRect.location() - flippedFl
owThreadPortionRect.location())); | 158 clippedRect.setLocation(regionLocation + (clippedRect.location() - flippedFl
owThreadPortionRect.location())); |
| 342 | 159 |
| 343 // Now switch to the region's writing mode coordinate space and let it repai
nt itself. | 160 // Now switch to the region's writing mode coordinate space and let it repai
nt itself. |
| 344 flipForWritingMode(clippedRect); | 161 flipForWritingMode(clippedRect); |
| 345 | 162 |
| 346 // Issue the repaint. | 163 // Issue the repaint. |
| 347 repaintRectangle(clippedRect); | 164 repaintRectangle(clippedRect); |
| 348 } | 165 } |
| 349 | 166 |
| 350 void RenderRegion::installFlowThread() | |
| 351 { | |
| 352 ASSERT(view()); | |
| 353 | |
| 354 m_flowThread = view()->flowThreadController()->ensureRenderFlowThreadWithNam
e(style()->regionThread()); | |
| 355 | |
| 356 // By now the flow thread should already be added to the rendering tree, | |
| 357 // so we go up the rendering parents and check that this region is not part
of the same | |
| 358 // flow that it actually needs to display. It would create a circular refere
nce. | |
| 359 RenderObject* parentObject = parent(); | |
| 360 m_parentNamedFlowThread = 0; | |
| 361 for ( ; parentObject; parentObject = parentObject->parent()) { | |
| 362 if (parentObject->isRenderNamedFlowThread()) { | |
| 363 m_parentNamedFlowThread = toRenderNamedFlowThread(parentObject); | |
| 364 // Do not take into account a region that links a flow with itself.
The dependency | |
| 365 // cannot change, so it is not worth adding it to the list. | |
| 366 if (m_flowThread == m_parentNamedFlowThread) | |
| 367 m_flowThread = 0; | |
| 368 break; | |
| 369 } | |
| 370 } | |
| 371 } | |
| 372 | |
| 373 void RenderRegion::attachRegion() | 167 void RenderRegion::attachRegion() |
| 374 { | 168 { |
| 375 if (documentBeingDestroyed()) | 169 if (documentBeingDestroyed()) |
| 376 return; | 170 return; |
| 377 | 171 |
| 378 // A region starts off invalid. | 172 // A region starts off invalid. |
| 379 setIsValid(false); | 173 setIsValid(false); |
| 380 | 174 |
| 381 // Initialize the flow thread reference and create the flow thread object if
needed. | |
| 382 // The flow thread lifetime is influenced by the number of regions attached
to it, | |
| 383 // and we are attaching the region to the flow thread. | |
| 384 installFlowThread(); | |
| 385 | |
| 386 if (!m_flowThread) | 175 if (!m_flowThread) |
| 387 return; | 176 return; |
| 388 | 177 |
| 389 // Only after adding the region to the thread, the region is marked to be va
lid. | 178 // Only after adding the region to the thread, the region is marked to be va
lid. |
| 390 m_flowThread->addRegionToThread(this); | 179 m_flowThread->addRegionToThread(this); |
| 391 | |
| 392 // The region just got attached to the flow thread, lets check whether | |
| 393 // it has region styling rules associated. | |
| 394 checkRegionStyle(); | |
| 395 | |
| 396 if (!isValid()) | |
| 397 return; | |
| 398 | |
| 399 m_hasAutoLogicalHeight = shouldHaveAutoLogicalHeight(); | |
| 400 if (hasAutoLogicalHeight()) | |
| 401 incrementAutoLogicalHeightCount(); | |
| 402 } | 180 } |
| 403 | 181 |
| 404 void RenderRegion::detachRegion() | 182 void RenderRegion::detachRegion() |
| 405 { | 183 { |
| 406 if (m_flowThread) { | 184 if (m_flowThread) { |
| 407 m_flowThread->removeRegionFromThread(this); | 185 m_flowThread->removeRegionFromThread(this); |
| 408 if (hasAutoLogicalHeight()) | 186 m_flowThread = 0; |
| 409 decrementAutoLogicalHeightCount(); | |
| 410 } | 187 } |
| 411 m_flowThread = 0; | |
| 412 } | |
| 413 | |
| 414 RenderBoxRegionInfo* RenderRegion::renderBoxRegionInfo(const RenderBox* box) con
st | |
| 415 { | |
| 416 ASSERT(isValid()); | |
| 417 return m_renderBoxRegionInfo.get(box); | |
| 418 } | |
| 419 | |
| 420 RenderBoxRegionInfo* RenderRegion::setRenderBoxRegionInfo(const RenderBox* box,
LayoutUnit logicalLeftInset, LayoutUnit logicalRightInset, | |
| 421 bool containingBlockChainIsInset) | |
| 422 { | |
| 423 ASSERT(isValid()); | |
| 424 | |
| 425 OwnPtr<RenderBoxRegionInfo>& boxInfo = m_renderBoxRegionInfo.add(box, nullpt
r).iterator->value; | |
| 426 if (boxInfo) | |
| 427 *boxInfo = RenderBoxRegionInfo(logicalLeftInset, logicalRightInset, cont
ainingBlockChainIsInset); | |
| 428 else | |
| 429 boxInfo = adoptPtr(new RenderBoxRegionInfo(logicalLeftInset, logicalRigh
tInset, containingBlockChainIsInset)); | |
| 430 | |
| 431 return boxInfo.get(); | |
| 432 } | |
| 433 | |
| 434 PassOwnPtr<RenderBoxRegionInfo> RenderRegion::takeRenderBoxRegionInfo(const Rend
erBox* box) | |
| 435 { | |
| 436 return m_renderBoxRegionInfo.take(box); | |
| 437 } | |
| 438 | |
| 439 void RenderRegion::removeRenderBoxRegionInfo(const RenderBox* box) | |
| 440 { | |
| 441 m_renderBoxRegionInfo.remove(box); | |
| 442 } | |
| 443 | |
| 444 void RenderRegion::deleteAllRenderBoxRegionInfo() | |
| 445 { | |
| 446 m_renderBoxRegionInfo.clear(); | |
| 447 } | 188 } |
| 448 | 189 |
| 449 LayoutUnit RenderRegion::logicalTopOfFlowThreadContentRect(const LayoutRect& rec
t) const | 190 LayoutUnit RenderRegion::logicalTopOfFlowThreadContentRect(const LayoutRect& rec
t) const |
| 450 { | 191 { |
| 451 ASSERT(isValid()); | 192 ASSERT(isValid()); |
| 452 return flowThread()->isHorizontalWritingMode() ? rect.y() : rect.x(); | 193 return flowThread()->isHorizontalWritingMode() ? rect.y() : rect.x(); |
| 453 } | 194 } |
| 454 | 195 |
| 455 LayoutUnit RenderRegion::logicalBottomOfFlowThreadContentRect(const LayoutRect&
rect) const | 196 LayoutUnit RenderRegion::logicalBottomOfFlowThreadContentRect(const LayoutRect&
rect) const |
| 456 { | 197 { |
| 457 ASSERT(isValid()); | 198 ASSERT(isValid()); |
| 458 return flowThread()->isHorizontalWritingMode() ? rect.maxY() : rect.maxX(); | 199 return flowThread()->isHorizontalWritingMode() ? rect.maxY() : rect.maxX(); |
| 459 } | 200 } |
| 460 | 201 |
| 461 void RenderRegion::setRegionObjectsRegionStyle() | |
| 462 { | |
| 463 if (!hasCustomRegionStyle()) | |
| 464 return; | |
| 465 | |
| 466 // Start from content nodes and recursively compute the style in region for
the render objects below. | |
| 467 // If the style in region was already computed, used that style instead of c
omputing a new one. | |
| 468 RenderNamedFlowThread* namedFlow = view()->flowThreadController()->ensureRen
derFlowThreadWithName(style()->regionThread()); | |
| 469 const NamedFlowContentNodes& contentNodes = namedFlow->contentNodes(); | |
| 470 | |
| 471 for (NamedFlowContentNodes::const_iterator iter = contentNodes.begin(), end
= contentNodes.end(); iter != end; ++iter) { | |
| 472 const Node* node = *iter; | |
| 473 // The list of content nodes contains also the nodes with display:none. | |
| 474 if (!node->renderer()) | |
| 475 continue; | |
| 476 | |
| 477 RenderObject* object = node->renderer(); | |
| 478 // If the content node does not flow any of its children in this region, | |
| 479 // we do not compute any style for them in this region. | |
| 480 if (!flowThread()->objectInFlowRegion(object, this)) | |
| 481 continue; | |
| 482 | |
| 483 // If the object has style in region, use that instead of computing a ne
w one. | |
| 484 RenderObjectRegionStyleMap::iterator it = m_renderObjectRegionStyle.find
(object); | |
| 485 RefPtr<RenderStyle> objectStyleInRegion; | |
| 486 bool objectRegionStyleCached = false; | |
| 487 if (it != m_renderObjectRegionStyle.end()) { | |
| 488 objectStyleInRegion = it->value.style; | |
| 489 ASSERT(it->value.cached); | |
| 490 objectRegionStyleCached = true; | |
| 491 } else { | |
| 492 objectStyleInRegion = computeStyleInRegion(object); | |
| 493 } | |
| 494 | |
| 495 setObjectStyleInRegion(object, objectStyleInRegion, objectRegionStyleCac
hed); | |
| 496 | |
| 497 computeChildrenStyleInRegion(object); | |
| 498 } | |
| 499 } | |
| 500 | |
| 501 void RenderRegion::restoreRegionObjectsOriginalStyle() | |
| 502 { | |
| 503 if (!hasCustomRegionStyle()) | |
| 504 return; | |
| 505 | |
| 506 RenderObjectRegionStyleMap temp; | |
| 507 for (RenderObjectRegionStyleMap::iterator iter = m_renderObjectRegionStyle.b
egin(), end = m_renderObjectRegionStyle.end(); iter != end; ++iter) { | |
| 508 RenderObject* object = const_cast<RenderObject*>(iter->key); | |
| 509 RefPtr<RenderStyle> objectRegionStyle = object->style(); | |
| 510 RefPtr<RenderStyle> objectOriginalStyle = iter->value.style; | |
| 511 object->setStyleInternal(objectOriginalStyle); | |
| 512 | |
| 513 bool shouldCacheRegionStyle = iter->value.cached; | |
| 514 if (!shouldCacheRegionStyle) { | |
| 515 // Check whether we should cache the computed style in region. | |
| 516 unsigned changedContextSensitiveProperties = ContextSensitivePropert
yNone; | |
| 517 StyleDifference styleDiff = objectOriginalStyle->diff(objectRegionSt
yle.get(), changedContextSensitiveProperties); | |
| 518 if (styleDiff < StyleDifferenceLayoutPositionedMovementOnly) | |
| 519 shouldCacheRegionStyle = true; | |
| 520 } | |
| 521 if (shouldCacheRegionStyle) { | |
| 522 ObjectRegionStyleInfo styleInfo; | |
| 523 styleInfo.style = objectRegionStyle; | |
| 524 styleInfo.cached = true; | |
| 525 temp.set(object, styleInfo); | |
| 526 } | |
| 527 } | |
| 528 | |
| 529 m_renderObjectRegionStyle.swap(temp); | |
| 530 } | |
| 531 | |
| 532 void RenderRegion::insertedIntoTree() | 202 void RenderRegion::insertedIntoTree() |
| 533 { | 203 { |
| 534 RenderBlock::insertedIntoTree(); | 204 RenderBlock::insertedIntoTree(); |
| 535 | 205 |
| 536 attachRegion(); | 206 attachRegion(); |
| 537 } | 207 } |
| 538 | 208 |
| 539 void RenderRegion::willBeRemovedFromTree() | 209 void RenderRegion::willBeRemovedFromTree() |
| 540 { | 210 { |
| 541 RenderBlock::willBeRemovedFromTree(); | 211 RenderBlock::willBeRemovedFromTree(); |
| 542 | 212 |
| 543 detachRegion(); | 213 detachRegion(); |
| 544 } | 214 } |
| 545 | 215 |
| 546 PassRefPtr<RenderStyle> RenderRegion::computeStyleInRegion(const RenderObject* o
bject) | |
| 547 { | |
| 548 ASSERT(object); | |
| 549 ASSERT(object->view()); | |
| 550 ASSERT(!object->isAnonymous()); | |
| 551 ASSERT(object->node() && object->node()->isElementNode()); | |
| 552 | |
| 553 // FIXME: Region styling fails for pseudo-elements because the renderers don
't have a node. | |
| 554 Element* element = toElement(object->node()); | |
| 555 RefPtr<RenderStyle> renderObjectRegionStyle = object->view()->document().ens
ureStyleResolver().styleForElement(element, 0, DisallowStyleSharing, MatchAllRul
es, this); | |
| 556 | |
| 557 return renderObjectRegionStyle.release(); | |
| 558 } | |
| 559 | |
| 560 void RenderRegion::computeChildrenStyleInRegion(const RenderObject* object) | |
| 561 { | |
| 562 for (RenderObject* child = object->lastChild(); child; child = child->previo
usSibling()) { | |
| 563 | |
| 564 RenderObjectRegionStyleMap::iterator it = m_renderObjectRegionStyle.find
(child); | |
| 565 | |
| 566 RefPtr<RenderStyle> childStyleInRegion; | |
| 567 bool objectRegionStyleCached = false; | |
| 568 if (it != m_renderObjectRegionStyle.end()) { | |
| 569 childStyleInRegion = it->value.style; | |
| 570 objectRegionStyleCached = true; | |
| 571 } else { | |
| 572 if (child->isAnonymous() || child->isInFlowRenderFlowThread()) | |
| 573 childStyleInRegion = RenderStyle::createAnonymousStyleWithDispla
y(object->style(), child->style()->display()); | |
| 574 else if (child->isText()) | |
| 575 childStyleInRegion = RenderStyle::clone(object->style()); | |
| 576 else | |
| 577 childStyleInRegion = computeStyleInRegion(child); | |
| 578 } | |
| 579 | |
| 580 setObjectStyleInRegion(child, childStyleInRegion, objectRegionStyleCache
d); | |
| 581 | |
| 582 computeChildrenStyleInRegion(child); | |
| 583 } | |
| 584 } | |
| 585 | |
| 586 void RenderRegion::setObjectStyleInRegion(RenderObject* object, PassRefPtr<Rende
rStyle> styleInRegion, bool objectRegionStyleCached) | |
| 587 { | |
| 588 ASSERT(object->flowThreadContainingBlock()); | |
| 589 | |
| 590 RefPtr<RenderStyle> objectOriginalStyle = object->style(); | |
| 591 object->setStyleInternal(styleInRegion); | |
| 592 | |
| 593 if (object->isBoxModelObject() && !object->hasBoxDecorations()) { | |
| 594 bool hasBoxDecorations = object->isTableCell() | |
| 595 || object->style()->hasBackground() | |
| 596 || object->style()->hasBorder() | |
| 597 || object->style()->hasAppearance() | |
| 598 || object->style()->boxShadow(); | |
| 599 object->setHasBoxDecorations(hasBoxDecorations); | |
| 600 } | |
| 601 | |
| 602 ObjectRegionStyleInfo styleInfo; | |
| 603 styleInfo.style = objectOriginalStyle; | |
| 604 styleInfo.cached = objectRegionStyleCached; | |
| 605 m_renderObjectRegionStyle.set(object, styleInfo); | |
| 606 } | |
| 607 | |
| 608 void RenderRegion::clearObjectStyleInRegion(const RenderObject* object) | |
| 609 { | |
| 610 ASSERT(object); | |
| 611 m_renderObjectRegionStyle.remove(object); | |
| 612 | |
| 613 // Clear the style for the children of this object. | |
| 614 for (RenderObject* child = object->lastChild(); child; child = child->previo
usSibling()) | |
| 615 clearObjectStyleInRegion(child); | |
| 616 } | |
| 617 | |
| 618 void RenderRegion::computeIntrinsicLogicalWidths(LayoutUnit& minLogicalWidth, La
youtUnit& maxLogicalWidth) const | 216 void RenderRegion::computeIntrinsicLogicalWidths(LayoutUnit& minLogicalWidth, La
youtUnit& maxLogicalWidth) const |
| 619 { | 217 { |
| 620 if (!isValid()) { | 218 if (!isValid()) { |
| 621 RenderBlock::computeIntrinsicLogicalWidths(minLogicalWidth, maxLogicalWi
dth); | 219 RenderBlock::computeIntrinsicLogicalWidths(minLogicalWidth, maxLogicalWi
dth); |
| 622 return; | 220 return; |
| 623 } | 221 } |
| 624 | 222 |
| 625 minLogicalWidth = m_flowThread->minPreferredLogicalWidth(); | 223 minLogicalWidth = m_flowThread->minPreferredLogicalWidth(); |
| 626 maxLogicalWidth = m_flowThread->maxPreferredLogicalWidth(); | 224 maxLogicalWidth = m_flowThread->maxPreferredLogicalWidth(); |
| 627 } | 225 } |
| 628 | 226 |
| 629 void RenderRegion::getRanges(Vector<RefPtr<Range> >& rangeObjects) const | |
| 630 { | |
| 631 RenderNamedFlowThread* namedFlow = view()->flowThreadController()->ensureRen
derFlowThreadWithName(style()->regionThread()); | |
| 632 namedFlow->getRanges(rangeObjects, this); | |
| 633 } | |
| 634 | |
| 635 void RenderRegion::updateLogicalHeight() | |
| 636 { | |
| 637 RenderBlock::updateLogicalHeight(); | |
| 638 | |
| 639 if (!hasAutoLogicalHeight()) | |
| 640 return; | |
| 641 | |
| 642 // We want to update the logical height based on the computed auto-height | |
| 643 // only if the view is in the layout phase in which all the | |
| 644 // auto logical height regions have a computed auto-height. | |
| 645 if (!m_flowThread->inConstrainedLayoutPhase()) | |
| 646 return; | |
| 647 | |
| 648 // There may be regions with auto logical height that during the prerequisit
e layout phase | |
| 649 // did not have the chance to layout flow thread content. Because of that, t
hese regions do not | |
| 650 // have a computedAutoHeight and they will not be able to fragment any flow | |
| 651 // thread content. | |
| 652 if (!hasComputedAutoHeight()) | |
| 653 return; | |
| 654 | |
| 655 LayoutUnit autoHeight = hasOverrideHeight() ? overrideLogicalContentHeight()
: computedAutoHeight(); | |
| 656 | |
| 657 LayoutUnit newLogicalHeight = autoHeight + borderAndPaddingLogicalHeight(); | |
| 658 ASSERT(newLogicalHeight < RenderFlowThread::maxLogicalHeight()); | |
| 659 if (newLogicalHeight > logicalHeight()) { | |
| 660 setLogicalHeight(newLogicalHeight); | |
| 661 // Recalculate position of the render block after new logical height is
set. | |
| 662 // (needed in absolute positioning case with bottom alignment for exampl
e) | |
| 663 RenderBlock::updateLogicalHeight(); | |
| 664 } | |
| 665 } | |
| 666 | |
| 667 Node* RenderRegion::nodeForRegion() const | |
| 668 { | |
| 669 if (parent() && isRenderNamedFlowFragment()) | |
| 670 return parent()->node(); | |
| 671 return node(); | |
| 672 } | |
| 673 | |
| 674 Node* RenderRegion::generatingNodeForRegion() const | |
| 675 { | |
| 676 if (parent() && isRenderNamedFlowFragment()) | |
| 677 return parent()->generatingNode(); | |
| 678 return generatingNode(); | |
| 679 } | |
| 680 | |
| 681 bool RenderRegion::isElementBasedRegion() const | |
| 682 { | |
| 683 Node* node = nodeForRegion(); | |
| 684 return node && node->isElementNode() && !node->isPseudoElement(); | |
| 685 } | |
| 686 | |
| 687 } // namespace WebCore | 227 } // namespace WebCore |
| OLD | NEW |