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