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