| OLD | NEW |
| (Empty) |
| 1 /* | |
| 2 * Copyright (C) 2013 Google Inc. 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 are | |
| 6 * met: | |
| 7 * | |
| 8 * * Redistributions of source code must retain the above copyright | |
| 9 * notice, this list of conditions and the following disclaimer. | |
| 10 * * Redistributions in binary form must reproduce the above | |
| 11 * copyright notice, this list of conditions and the following disclaimer | |
| 12 * in the documentation and/or other materials provided with the | |
| 13 * distribution. | |
| 14 * * Neither the name of Google Inc. nor the names of its | |
| 15 * contributors may be used to endorse or promote products derived from | |
| 16 * this software without specific prior written permission. | |
| 17 * | |
| 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
| 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
| 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
| 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
| 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
| 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
| 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
| 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
| 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
| 29 */ | |
| 30 | |
| 31 #include "sky/engine/config.h" | |
| 32 #include "sky/engine/core/rendering/RenderBlockFlow.h" | |
| 33 | |
| 34 #include "sky/engine/core/frame/FrameView.h" | |
| 35 #include "sky/engine/core/frame/LocalFrame.h" | |
| 36 #include "sky/engine/core/frame/Settings.h" | |
| 37 #include "sky/engine/core/rendering/BidiRun.h" | |
| 38 #include "sky/engine/core/rendering/HitTestLocation.h" | |
| 39 #include "sky/engine/core/rendering/RenderLayer.h" | |
| 40 #include "sky/engine/core/rendering/RenderText.h" | |
| 41 #include "sky/engine/core/rendering/RenderView.h" | |
| 42 #include "sky/engine/core/rendering/line/LineWidth.h" | |
| 43 #include "sky/engine/platform/text/BidiTextRun.h" | |
| 44 | |
| 45 namespace blink { | |
| 46 | |
| 47 RenderBlockFlow::RenderBlockFlow(ContainerNode* node) | |
| 48 : RenderBlock(node) | |
| 49 { | |
| 50 } | |
| 51 | |
| 52 RenderBlockFlow::~RenderBlockFlow() | |
| 53 { | |
| 54 } | |
| 55 | |
| 56 RenderBlockFlow* RenderBlockFlow::createAnonymous(Document* document) | |
| 57 { | |
| 58 RenderBlockFlow* renderer = new RenderBlockFlow(0); | |
| 59 renderer->setDocumentForAnonymous(document); | |
| 60 return renderer; | |
| 61 } | |
| 62 | |
| 63 void RenderBlockFlow::layout() | |
| 64 { | |
| 65 ASSERT(needsLayout()); | |
| 66 ASSERT(isInlineBlock() || !isInline()); | |
| 67 | |
| 68 if (simplifiedLayout()) | |
| 69 return; | |
| 70 | |
| 71 SubtreeLayoutScope layoutScope(*this); | |
| 72 | |
| 73 layoutBlockFlow(layoutScope); | |
| 74 | |
| 75 updateLayerTransformAfterLayout(); | |
| 76 | |
| 77 clearNeedsLayout(); | |
| 78 } | |
| 79 | |
| 80 inline void RenderBlockFlow::layoutBlockFlow(SubtreeLayoutScope& layoutScope) | |
| 81 { | |
| 82 LayoutUnit oldLeft = logicalLeft(); | |
| 83 bool logicalWidthChanged = updateLogicalWidthAndColumnWidth(); | |
| 84 bool relayoutChildren = logicalWidthChanged; | |
| 85 | |
| 86 LayoutUnit beforeEdge = borderBefore() + paddingBefore(); | |
| 87 LayoutUnit afterEdge = borderAfter() + paddingAfter(); | |
| 88 LayoutUnit previousHeight = logicalHeight(); | |
| 89 setLogicalHeight(beforeEdge); | |
| 90 | |
| 91 layoutChildren(relayoutChildren, layoutScope, beforeEdge, afterEdge); | |
| 92 | |
| 93 LayoutUnit oldClientAfterEdge = clientLogicalBottom(); | |
| 94 | |
| 95 updateLogicalHeight(); | |
| 96 | |
| 97 if (previousHeight != logicalHeight()) | |
| 98 relayoutChildren = true; | |
| 99 | |
| 100 layoutPositionedObjects(relayoutChildren, oldLeft != logicalLeft() ? ForcedL
ayoutAfterContainingBlockMoved : DefaultLayout); | |
| 101 | |
| 102 // Add overflow from children (unless we're multi-column, since in that case
all our child overflow is clipped anyway). | |
| 103 computeOverflow(oldClientAfterEdge); | |
| 104 } | |
| 105 | |
| 106 void RenderBlockFlow::determineLogicalLeftPositionForChild(RenderBox* child) | |
| 107 { | |
| 108 LayoutUnit startPosition = borderStart() + paddingStart(); | |
| 109 LayoutUnit totalAvailableLogicalWidth = borderAndPaddingLogicalWidth() + ava
ilableLogicalWidth(); | |
| 110 | |
| 111 LayoutUnit childMarginStart = marginStartForChild(child); | |
| 112 LayoutUnit newPosition = startPosition + childMarginStart; | |
| 113 | |
| 114 // If the child has an offset from the content edge to avoid floats then use
that, otherwise let any negative | |
| 115 // margin pull it back over the content edge or any positive margin push it
out. | |
| 116 if (child->style()->marginStartUsing(style()).isAuto()) | |
| 117 newPosition = std::max(newPosition, childMarginStart); | |
| 118 | |
| 119 child->setX(style()->isLeftToRightDirection() ? newPosition : totalAvailable
LogicalWidth - newPosition - logicalWidthForChild(child)); | |
| 120 } | |
| 121 | |
| 122 void RenderBlockFlow::layoutBlockChild(RenderBox* child) | |
| 123 { | |
| 124 child->computeAndSetBlockDirectionMargins(this); | |
| 125 LayoutUnit marginBefore = marginBeforeForChild(child); | |
| 126 child->setY(logicalHeight() + marginBefore); | |
| 127 child->layoutIfNeeded(); | |
| 128 determineLogicalLeftPositionForChild(child); | |
| 129 setLogicalHeight(logicalHeight() + marginBefore + logicalHeightForChild(chil
d) + marginAfterForChild(child)); | |
| 130 } | |
| 131 | |
| 132 void RenderBlockFlow::layoutChildren(bool relayoutChildren, SubtreeLayoutScope&
layoutScope, LayoutUnit beforeEdge, LayoutUnit afterEdge) | |
| 133 { | |
| 134 dirtyForLayoutFromPercentageHeightDescendants(layoutScope); | |
| 135 | |
| 136 RenderBox* next = firstChildBox(); | |
| 137 RenderBox* lastNormalFlowChild = 0; | |
| 138 | |
| 139 while (next) { | |
| 140 RenderBox* child = next; | |
| 141 next = child->nextSiblingBox(); | |
| 142 | |
| 143 updateBlockChildDirtyBitsBeforeLayout(relayoutChildren, child); | |
| 144 | |
| 145 if (child->isOutOfFlowPositioned()) { | |
| 146 child->containingBlock()->insertPositionedObject(child); | |
| 147 continue; | |
| 148 } | |
| 149 | |
| 150 // Lay out the child. | |
| 151 layoutBlockChild(child); | |
| 152 lastNormalFlowChild = child; | |
| 153 } | |
| 154 | |
| 155 // Negative margins can cause our height to shrink below our minimal height
(border/padding). | |
| 156 // If this happens, ensure that the computed height is increased to the mini
mal height. | |
| 157 setLogicalHeight(std::max(logicalHeight() + afterEdge, beforeEdge + afterEdg
e)); | |
| 158 } | |
| 159 | |
| 160 RootInlineBox* RenderBlockFlow::createAndAppendRootInlineBox() | |
| 161 { | |
| 162 RootInlineBox* rootBox = createRootInlineBox(); | |
| 163 m_lineBoxes.appendLineBox(rootBox); | |
| 164 | |
| 165 return rootBox; | |
| 166 } | |
| 167 | |
| 168 void RenderBlockFlow::deleteLineBoxTree() | |
| 169 { | |
| 170 m_lineBoxes.deleteLineBoxTree(); | |
| 171 } | |
| 172 | |
| 173 void RenderBlockFlow::addChild(RenderObject* newChild, RenderObject* beforeChild
) | |
| 174 { | |
| 175 RenderBlock::addChild(newChild, beforeChild); | |
| 176 } | |
| 177 | |
| 178 LayoutUnit RenderBlockFlow::logicalLeftSelectionOffset(RenderBlock* rootBlock, L
ayoutUnit position) | |
| 179 { | |
| 180 LayoutUnit logicalLeft = logicalLeftOffsetForLine(false); | |
| 181 if (logicalLeft == logicalLeftOffsetForContent()) | |
| 182 return RenderBlock::logicalLeftSelectionOffset(rootBlock, position); | |
| 183 | |
| 184 RenderBlock* cb = this; | |
| 185 while (cb != rootBlock) { | |
| 186 logicalLeft += cb->logicalLeft(); | |
| 187 cb = cb->containingBlock(); | |
| 188 } | |
| 189 return logicalLeft; | |
| 190 } | |
| 191 | |
| 192 LayoutUnit RenderBlockFlow::logicalRightSelectionOffset(RenderBlock* rootBlock,
LayoutUnit position) | |
| 193 { | |
| 194 LayoutUnit logicalRight = logicalRightOffsetForLine(false); | |
| 195 if (logicalRight == logicalRightOffsetForContent()) | |
| 196 return RenderBlock::logicalRightSelectionOffset(rootBlock, position); | |
| 197 | |
| 198 RenderBlock* cb = this; | |
| 199 while (cb != rootBlock) { | |
| 200 logicalRight += cb->logicalLeft(); | |
| 201 cb = cb->containingBlock(); | |
| 202 } | |
| 203 return logicalRight; | |
| 204 } | |
| 205 | |
| 206 RootInlineBox* RenderBlockFlow::createRootInlineBox() | |
| 207 { | |
| 208 return new RootInlineBox(*this); | |
| 209 } | |
| 210 | |
| 211 static void updateLogicalWidthForLeftAlignedBlock(bool isLeftToRightDirection, B
idiRun* trailingSpaceRun, float& logicalLeft, float& totalLogicalWidth, float av
ailableLogicalWidth) | |
| 212 { | |
| 213 // The direction of the block should determine what happens with wide lines. | |
| 214 // In particular with RTL blocks, wide lines should still spill out to the l
eft. | |
| 215 if (isLeftToRightDirection) { | |
| 216 if (totalLogicalWidth > availableLogicalWidth && trailingSpaceRun) | |
| 217 trailingSpaceRun->m_box->setLogicalWidth(std::max<float>(0, trailing
SpaceRun->m_box->logicalWidth() - totalLogicalWidth + availableLogicalWidth)); | |
| 218 return; | |
| 219 } | |
| 220 | |
| 221 if (trailingSpaceRun) | |
| 222 trailingSpaceRun->m_box->setLogicalWidth(0); | |
| 223 else if (totalLogicalWidth > availableLogicalWidth) | |
| 224 logicalLeft -= (totalLogicalWidth - availableLogicalWidth); | |
| 225 } | |
| 226 | |
| 227 static void updateLogicalWidthForRightAlignedBlock(bool isLeftToRightDirection,
BidiRun* trailingSpaceRun, float& logicalLeft, float& totalLogicalWidth, float a
vailableLogicalWidth) | |
| 228 { | |
| 229 // Wide lines spill out of the block based off direction. | |
| 230 // So even if text-align is right, if direction is LTR, wide lines should ov
erflow out of the right | |
| 231 // side of the block. | |
| 232 if (isLeftToRightDirection) { | |
| 233 if (trailingSpaceRun) { | |
| 234 totalLogicalWidth -= trailingSpaceRun->m_box->logicalWidth(); | |
| 235 trailingSpaceRun->m_box->setLogicalWidth(0); | |
| 236 } | |
| 237 if (totalLogicalWidth < availableLogicalWidth) | |
| 238 logicalLeft += availableLogicalWidth - totalLogicalWidth; | |
| 239 return; | |
| 240 } | |
| 241 | |
| 242 if (totalLogicalWidth > availableLogicalWidth && trailingSpaceRun) { | |
| 243 trailingSpaceRun->m_box->setLogicalWidth(std::max<float>(0, trailingSpac
eRun->m_box->logicalWidth() - totalLogicalWidth + availableLogicalWidth)); | |
| 244 totalLogicalWidth -= trailingSpaceRun->m_box->logicalWidth(); | |
| 245 } else | |
| 246 logicalLeft += availableLogicalWidth - totalLogicalWidth; | |
| 247 } | |
| 248 | |
| 249 static void updateLogicalWidthForCenterAlignedBlock(bool isLeftToRightDirection,
BidiRun* trailingSpaceRun, float& logicalLeft, float& totalLogicalWidth, float
availableLogicalWidth) | |
| 250 { | |
| 251 float trailingSpaceWidth = 0; | |
| 252 if (trailingSpaceRun) { | |
| 253 totalLogicalWidth -= trailingSpaceRun->m_box->logicalWidth(); | |
| 254 trailingSpaceWidth = std::min(trailingSpaceRun->m_box->logicalWidth(), (
availableLogicalWidth - totalLogicalWidth + 1) / 2); | |
| 255 trailingSpaceRun->m_box->setLogicalWidth(std::max<float>(0, trailingSpac
eWidth)); | |
| 256 } | |
| 257 if (isLeftToRightDirection) | |
| 258 logicalLeft += std::max<float>((availableLogicalWidth - totalLogicalWidt
h) / 2, 0); | |
| 259 else | |
| 260 logicalLeft += totalLogicalWidth > availableLogicalWidth ? (availableLog
icalWidth - totalLogicalWidth) : (availableLogicalWidth - totalLogicalWidth) / 2
- trailingSpaceWidth; | |
| 261 } | |
| 262 | |
| 263 void RenderBlockFlow::updateLogicalWidthForAlignment(const ETextAlign& textAlign
, const RootInlineBox* rootInlineBox, BidiRun* trailingSpaceRun, float& logicalL
eft, float& totalLogicalWidth, float& availableLogicalWidth, unsigned expansionO
pportunityCount) | |
| 264 { | |
| 265 TextDirection direction; | |
| 266 if (rootInlineBox && rootInlineBox->renderer().style()->unicodeBidi() == Pla
intext) | |
| 267 direction = rootInlineBox->direction(); | |
| 268 else | |
| 269 direction = style()->direction(); | |
| 270 | |
| 271 // Armed with the total width of the line (without justification), | |
| 272 // we now examine our text-align property in order to determine where to pos
ition the | |
| 273 // objects horizontally. The total width of the line can be increased if we
end up | |
| 274 // justifying text. | |
| 275 switch (textAlign) { | |
| 276 case LEFT: | |
| 277 updateLogicalWidthForLeftAlignedBlock(style()->isLeftToRightDirection(),
trailingSpaceRun, logicalLeft, totalLogicalWidth, availableLogicalWidth); | |
| 278 break; | |
| 279 case RIGHT: | |
| 280 updateLogicalWidthForRightAlignedBlock(style()->isLeftToRightDirection()
, trailingSpaceRun, logicalLeft, totalLogicalWidth, availableLogicalWidth); | |
| 281 break; | |
| 282 case CENTER: | |
| 283 updateLogicalWidthForCenterAlignedBlock(style()->isLeftToRightDirection(
), trailingSpaceRun, logicalLeft, totalLogicalWidth, availableLogicalWidth); | |
| 284 break; | |
| 285 case JUSTIFY: | |
| 286 adjustInlineDirectionLineBounds(expansionOpportunityCount, logicalLeft,
availableLogicalWidth); | |
| 287 if (expansionOpportunityCount) { | |
| 288 if (trailingSpaceRun) { | |
| 289 totalLogicalWidth -= trailingSpaceRun->m_box->logicalWidth(); | |
| 290 trailingSpaceRun->m_box->setLogicalWidth(0); | |
| 291 } | |
| 292 break; | |
| 293 } | |
| 294 // Fall through | |
| 295 case TASTART: | |
| 296 if (direction == LTR) | |
| 297 updateLogicalWidthForLeftAlignedBlock(style()->isLeftToRightDirectio
n(), trailingSpaceRun, logicalLeft, totalLogicalWidth, availableLogicalWidth); | |
| 298 else | |
| 299 updateLogicalWidthForRightAlignedBlock(style()->isLeftToRightDirecti
on(), trailingSpaceRun, logicalLeft, totalLogicalWidth, availableLogicalWidth); | |
| 300 break; | |
| 301 case TAEND: | |
| 302 if (direction == LTR) | |
| 303 updateLogicalWidthForRightAlignedBlock(style()->isLeftToRightDirecti
on(), trailingSpaceRun, logicalLeft, totalLogicalWidth, availableLogicalWidth); | |
| 304 else | |
| 305 updateLogicalWidthForLeftAlignedBlock(style()->isLeftToRightDirectio
n(), trailingSpaceRun, logicalLeft, totalLogicalWidth, availableLogicalWidth); | |
| 306 break; | |
| 307 } | |
| 308 } | |
| 309 | |
| 310 LayoutUnit RenderBlockFlow::startAlignedOffsetForLine(bool firstLine) | |
| 311 { | |
| 312 ETextAlign textAlign = style()->textAlign(); | |
| 313 | |
| 314 if (textAlign == TASTART) // FIXME: Handle TAEND here | |
| 315 return startOffsetForLine(firstLine); | |
| 316 | |
| 317 // updateLogicalWidthForAlignment() handles the direction of the block so no
need to consider it here | |
| 318 float totalLogicalWidth = 0; | |
| 319 float logicalLeft = logicalLeftOffsetForLine(false).toFloat(); | |
| 320 float availableLogicalWidth = logicalRightOffsetForLine(false) - logicalLeft
; | |
| 321 updateLogicalWidthForAlignment(textAlign, 0, 0, logicalLeft, totalLogicalWid
th, availableLogicalWidth, 0); | |
| 322 | |
| 323 if (!style()->isLeftToRightDirection()) | |
| 324 return logicalWidth() - logicalLeft; | |
| 325 return logicalLeft; | |
| 326 } | |
| 327 | |
| 328 } // namespace blink | |
| OLD | NEW |