| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (C) 2008 Apple Inc. All rights reserved. | 2 * Copyright (C) 2008 Apple Inc. 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 copyright | 8 * 1. Redistributions of source code must retain the above copyright |
| 9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
| 10 * 2. Redistributions in binary form must reproduce the above copyright | 10 * 2. Redistributions in binary form must reproduce the above copyright |
| (...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 160 } else { | 160 } else { |
| 161 physicalStart += offset.x(); | 161 physicalStart += offset.x(); |
| 162 return cullRect.intersectsHorizontalRange(physicalStart, | 162 return cullRect.intersectsHorizontalRange(physicalStart, |
| 163 physicalStart + physicalExtent); | 163 physicalStart + physicalExtent); |
| 164 } | 164 } |
| 165 } | 165 } |
| 166 | 166 |
| 167 bool LineBoxList::anyLineIntersectsRect(LineLayoutBoxModel layoutObject, | 167 bool LineBoxList::anyLineIntersectsRect(LineLayoutBoxModel layoutObject, |
| 168 const CullRect& cullRect, | 168 const CullRect& cullRect, |
| 169 const LayoutPoint& offset) const { | 169 const LayoutPoint& offset) const { |
| 170 // We can check the first box and last box and avoid painting/hit testing if w
e don't | 170 // We can check the first box and last box and avoid painting/hit testing if |
| 171 // intersect. This is a quick short-circuit that we can take to avoid walking
any lines. | 171 // we don't intersect. This is a quick short-circuit that we can take to avoid |
| 172 // walking any lines. |
| 172 // FIXME: This check is flawed in the following extremely obscure way: | 173 // FIXME: This check is flawed in the following extremely obscure way: |
| 173 // if some line in the middle has a huge overflow, it might actually extend be
low the last line. | 174 // if some line in the middle has a huge overflow, it might actually extend |
| 175 // below the last line. |
| 174 RootInlineBox& firstRootBox = firstLineBox()->root(); | 176 RootInlineBox& firstRootBox = firstLineBox()->root(); |
| 175 RootInlineBox& lastRootBox = lastLineBox()->root(); | 177 RootInlineBox& lastRootBox = lastLineBox()->root(); |
| 176 LayoutUnit firstLineTop = | 178 LayoutUnit firstLineTop = |
| 177 firstLineBox()->logicalTopVisualOverflow(firstRootBox.lineTop()); | 179 firstLineBox()->logicalTopVisualOverflow(firstRootBox.lineTop()); |
| 178 LayoutUnit lastLineBottom = | 180 LayoutUnit lastLineBottom = |
| 179 lastLineBox()->logicalBottomVisualOverflow(lastRootBox.lineBottom()); | 181 lastLineBox()->logicalBottomVisualOverflow(lastRootBox.lineBottom()); |
| 180 | 182 |
| 181 return rangeIntersectsRect(layoutObject, firstLineTop, lastLineBottom, | 183 return rangeIntersectsRect(layoutObject, firstLineTop, lastLineBottom, |
| 182 cullRect, offset); | 184 cullRect, offset); |
| 183 } | 185 } |
| (...skipping 13 matching lines...) Expand all Loading... |
| 197 } | 199 } |
| 198 | 200 |
| 199 bool LineBoxList::hitTest(LineLayoutBoxModel layoutObject, | 201 bool LineBoxList::hitTest(LineLayoutBoxModel layoutObject, |
| 200 HitTestResult& result, | 202 HitTestResult& result, |
| 201 const HitTestLocation& locationInContainer, | 203 const HitTestLocation& locationInContainer, |
| 202 const LayoutPoint& accumulatedOffset, | 204 const LayoutPoint& accumulatedOffset, |
| 203 HitTestAction hitTestAction) const { | 205 HitTestAction hitTestAction) const { |
| 204 if (hitTestAction != HitTestForeground) | 206 if (hitTestAction != HitTestForeground) |
| 205 return false; | 207 return false; |
| 206 | 208 |
| 207 ASSERT( | 209 // The only way an inline could hit test like this is if it has a layer. |
| 208 layoutObject.isLayoutBlock() || | 210 DCHECK(layoutObject.isLayoutBlock() || |
| 209 (layoutObject.isLayoutInline() && | 211 (layoutObject.isLayoutInline() && layoutObject.hasLayer())); |
| 210 layoutObject | |
| 211 .hasLayer())); // The only way an inline could hit test like this is
if it has a layer. | |
| 212 | 212 |
| 213 // If we have no lines then we have no work to do. | 213 // If we have no lines then we have no work to do. |
| 214 if (!firstLineBox()) | 214 if (!firstLineBox()) |
| 215 return false; | 215 return false; |
| 216 | 216 |
| 217 LayoutPoint point = locationInContainer.point(); | 217 LayoutPoint point = locationInContainer.point(); |
| 218 IntRect hitSearchBoundingBox = locationInContainer.boundingBox(); | 218 IntRect hitSearchBoundingBox = locationInContainer.boundingBox(); |
| 219 | 219 |
| 220 CullRect cullRect(firstLineBox()->isHorizontal() | 220 CullRect cullRect(firstLineBox()->isHorizontal() |
| 221 ? IntRect(point.x().toInt(), hitSearchBoundingBox.y(), | 221 ? IntRect(point.x().toInt(), hitSearchBoundingBox.y(), |
| 222 1, hitSearchBoundingBox.height()) | 222 1, hitSearchBoundingBox.height()) |
| 223 : IntRect(hitSearchBoundingBox.x(), point.y().toInt(), | 223 : IntRect(hitSearchBoundingBox.x(), point.y().toInt(), |
| 224 hitSearchBoundingBox.width(), 1)); | 224 hitSearchBoundingBox.width(), 1)); |
| 225 | 225 |
| 226 if (!anyLineIntersectsRect(layoutObject, cullRect, accumulatedOffset)) | 226 if (!anyLineIntersectsRect(layoutObject, cullRect, accumulatedOffset)) |
| 227 return false; | 227 return false; |
| 228 | 228 |
| 229 // See if our root lines contain the point. If so, then we hit test | 229 // See if our root lines contain the point. If so, then we hit test them |
| 230 // them further. Note that boxes can easily overlap, so we can't make any ass
umptions | 230 // further. Note that boxes can easily overlap, so we can't make any |
| 231 // based off positions of our first line box or our last line box. | 231 // assumptions based off positions of our first line box or our last line box. |
| 232 for (InlineFlowBox* curr = lastLineBox(); curr; curr = curr->prevLineBox()) { | 232 for (InlineFlowBox* curr = lastLineBox(); curr; curr = curr->prevLineBox()) { |
| 233 RootInlineBox& root = curr->root(); | 233 RootInlineBox& root = curr->root(); |
| 234 if (rangeIntersectsRect( | 234 if (rangeIntersectsRect( |
| 235 layoutObject, curr->logicalTopVisualOverflow(root.lineTop()), | 235 layoutObject, curr->logicalTopVisualOverflow(root.lineTop()), |
| 236 curr->logicalBottomVisualOverflow(root.lineBottom()), cullRect, | 236 curr->logicalBottomVisualOverflow(root.lineBottom()), cullRect, |
| 237 accumulatedOffset)) { | 237 accumulatedOffset)) { |
| 238 bool inside = | 238 bool inside = |
| 239 curr->nodeAtPoint(result, locationInContainer, accumulatedOffset, | 239 curr->nodeAtPoint(result, locationInContainer, accumulatedOffset, |
| 240 root.lineTop(), root.lineBottom()); | 240 root.lineTop(), root.lineBottom()); |
| 241 if (inside) { | 241 if (inside) { |
| (...skipping 13 matching lines...) Expand all Loading... |
| 255 bool canDirtyAncestors) { | 255 bool canDirtyAncestors) { |
| 256 if (!container.parent() || | 256 if (!container.parent() || |
| 257 (container.isLayoutBlock() && | 257 (container.isLayoutBlock() && |
| 258 (container.selfNeedsLayout() || !container.isLayoutBlockFlow()))) | 258 (container.selfNeedsLayout() || !container.isLayoutBlockFlow()))) |
| 259 return; | 259 return; |
| 260 | 260 |
| 261 LineLayoutInline inlineContainer = container.isLayoutInline() | 261 LineLayoutInline inlineContainer = container.isLayoutInline() |
| 262 ? LineLayoutInline(container) | 262 ? LineLayoutInline(container) |
| 263 : LineLayoutInline(); | 263 : LineLayoutInline(); |
| 264 | 264 |
| 265 // If we are attaching children dirtying lines is unnecessary as we will do a
full layout | 265 // If we are attaching children dirtying lines is unnecessary as we will do a |
| 266 // of the inline's contents anyway. | 266 // full layout of the inline's contents anyway. |
| 267 if (inlineContainer && inlineContainer.node() && | 267 if (inlineContainer && inlineContainer.node() && |
| 268 inlineContainer.node()->needsAttach()) | 268 inlineContainer.node()->needsAttach()) |
| 269 return; | 269 return; |
| 270 | 270 |
| 271 InlineBox* firstBox = inlineContainer | 271 InlineBox* firstBox = inlineContainer |
| 272 ? inlineContainer.firstLineBoxIncludingCulling() | 272 ? inlineContainer.firstLineBoxIncludingCulling() |
| 273 : firstLineBox(); | 273 : firstLineBox(); |
| 274 | 274 |
| 275 // If we have no first line box, then just bail early. | 275 // If we have no first line box, then just bail early. |
| 276 if (!firstBox) { | 276 if (!firstBox) { |
| 277 // For an empty inline, go ahead and propagate the check up to our parent, u
nless the parent | 277 // For an empty inline, go ahead and propagate the check up to our parent, |
| 278 // is already dirty. | 278 // unless the parent is already dirty. |
| 279 if (container.isInline() && !container.ancestorLineBoxDirty() && | 279 if (container.isInline() && !container.ancestorLineBoxDirty() && |
| 280 canDirtyAncestors) { | 280 canDirtyAncestors) { |
| 281 container.parent().dirtyLinesFromChangedChild(container); | 281 container.parent().dirtyLinesFromChangedChild(container); |
| 282 container | 282 // Mark the container to avoid dirtying the same lines again across |
| 283 .setAncestorLineBoxDirty(); // Mark the container to avoid dirtying t
he same lines again across multiple destroy() calls of the same subtree. | 283 // multiple destroy() calls of the same subtree. |
| 284 container.setAncestorLineBoxDirty(); |
| 284 } | 285 } |
| 285 return; | 286 return; |
| 286 } | 287 } |
| 287 | 288 |
| 288 // Try to figure out which line box we belong in. First try to find a previou
s | 289 // Try to figure out which line box we belong in. First try to find a previous |
| 289 // line box by examining our siblings. If we didn't find a line box, then use
our | 290 // line box by examining our siblings. If we didn't find a line box, then use |
| 290 // parent's first line box. | 291 // our parent's first line box. |
| 291 RootInlineBox* box = nullptr; | 292 RootInlineBox* box = nullptr; |
| 292 LineLayoutItem curr = nullptr; | 293 LineLayoutItem curr = nullptr; |
| 293 for (curr = child.previousSibling(); curr; curr = curr.previousSibling()) { | 294 for (curr = child.previousSibling(); curr; curr = curr.previousSibling()) { |
| 294 if (curr.isFloatingOrOutOfFlowPositioned()) | 295 if (curr.isFloatingOrOutOfFlowPositioned()) |
| 295 continue; | 296 continue; |
| 296 | 297 |
| 297 if (curr.isAtomicInlineLevel()) { | 298 if (curr.isAtomicInlineLevel()) { |
| 298 InlineBox* wrapper = LineLayoutBox(curr).inlineBoxWrapper(); | 299 InlineBox* wrapper = LineLayoutBox(curr).inlineBoxWrapper(); |
| 299 if (wrapper) | 300 if (wrapper) |
| 300 box = &wrapper->root(); | 301 box = &wrapper->root(); |
| 301 } else if (curr.isText()) { | 302 } else if (curr.isText()) { |
| 302 InlineTextBox* textBox = LineLayoutText(curr).lastTextBox(); | 303 InlineTextBox* textBox = LineLayoutText(curr).lastTextBox(); |
| 303 if (textBox) | 304 if (textBox) |
| 304 box = &textBox->root(); | 305 box = &textBox->root(); |
| 305 } else if (curr.isLayoutInline()) { | 306 } else if (curr.isLayoutInline()) { |
| 306 InlineBox* lastSiblingBox = | 307 InlineBox* lastSiblingBox = |
| 307 LineLayoutInline(curr).lastLineBoxIncludingCulling(); | 308 LineLayoutInline(curr).lastLineBoxIncludingCulling(); |
| 308 if (lastSiblingBox) | 309 if (lastSiblingBox) |
| 309 box = &lastSiblingBox->root(); | 310 box = &lastSiblingBox->root(); |
| 310 } | 311 } |
| 311 | 312 |
| 312 if (box) | 313 if (box) |
| 313 break; | 314 break; |
| 314 } | 315 } |
| 315 if (!box) { | 316 if (!box) { |
| 316 if (inlineContainer && !inlineContainer.alwaysCreateLineBoxes()) { | 317 if (inlineContainer && !inlineContainer.alwaysCreateLineBoxes()) { |
| 317 // https://bugs.webkit.org/show_bug.cgi?id=60778 | 318 // https://bugs.webkit.org/show_bug.cgi?id=60778 |
| 318 // We may have just removed a <br> with no line box that was our first chi
ld. In this case | 319 // We may have just removed a <br> with no line box that was our first |
| 319 // we won't find a previous sibling, but firstBox can be pointing to a fol
lowing sibling. | 320 // child. In this case we won't find a previous sibling, but firstBox can |
| 320 // This isn't good enough, since we won't locate the root line box that en
closes the removed | 321 // be pointing to a following sibling. This isn't good enough, since we |
| 321 // <br>. We have to just over-invalidate a bit and go up to our parent. | 322 // won't locate the root line box that encloses the removed <br>. We have |
| 323 // to just over-invalidate a bit and go up to our parent. |
| 322 if (!inlineContainer.ancestorLineBoxDirty() && canDirtyAncestors) { | 324 if (!inlineContainer.ancestorLineBoxDirty() && canDirtyAncestors) { |
| 323 inlineContainer.parent().dirtyLinesFromChangedChild(inlineContainer); | 325 inlineContainer.parent().dirtyLinesFromChangedChild(inlineContainer); |
| 324 inlineContainer | 326 // Mark the container to avoid dirtying the same lines again across |
| 325 .setAncestorLineBoxDirty(); // Mark the container to avoid dirtying
the same lines again across multiple destroy() calls of the same subtree. | 327 // multiple destroy() calls of the same subtree. |
| 328 inlineContainer.setAncestorLineBoxDirty(); |
| 326 } | 329 } |
| 327 return; | 330 return; |
| 328 } | 331 } |
| 329 box = &firstBox->root(); | 332 box = &firstBox->root(); |
| 330 } | 333 } |
| 331 | 334 |
| 332 // If we found a line box, then dirty it. | 335 // If we found a line box, then dirty it. |
| 333 if (box) { | 336 if (box) { |
| 334 box->markDirty(); | 337 box->markDirty(); |
| 335 | 338 |
| 336 // dirty the adjacent lines that might be affected | 339 // dirty the adjacent lines that might be affected |
| 337 // NOTE: we dirty the previous line because RootInlineBox objects cache | 340 // NOTE: we dirty the previous line because RootInlineBox objects cache |
| 338 // the address of the first object on the next line after a BR, which we may
be | 341 // the address of the first object on the next line after a BR, which we may |
| 339 // invalidating here. For more info, see how LayoutBlock::layoutInlineChild
ren | 342 // be invalidating here. For more info, see how LayoutBlock:: |
| 340 // calls setLineBreakInfo with the result of findNextLineBreak. findNextLin
eBreak, | 343 // layoutInlineChildren calls setLineBreakInfo with the result of |
| 341 // despite the name, actually returns the first LayoutObject after the BR. | 344 // findNextLineBreak. findNextLineBreak, despite the name, actually returns |
| 342 // <rdar://problem/3849947> "Typing after pasting line does not appear until
after window resize." | 345 // the first LayoutObject after the BR. <rdar://problem/3849947> "Typing |
| 346 // after pasting line does not appear until after window resize." |
| 343 if (RootInlineBox* prevRootBox = box->prevRootBox()) | 347 if (RootInlineBox* prevRootBox = box->prevRootBox()) |
| 344 prevRootBox->markDirty(); | 348 prevRootBox->markDirty(); |
| 345 // If |child| or any of its immediately previous siblings with culled linebo
xes is the object after a line-break in |box| or the linebox after it | 349 // If |child| or any of its immediately previous siblings with culled |
| 346 // then that means |child| actually sits on the linebox after |box| (or is i
ts line-break object) and so we need to dirty it as well. | 350 // lineboxes is the object after a line-break in |box| or the linebox after |
| 351 // it then that means |child| actually sits on the linebox after |box| (or |
| 352 // is its line-break object) and so we need to dirty it as well. |
| 347 if (RootInlineBox* nextRootBox = box->nextRootBox()) | 353 if (RootInlineBox* nextRootBox = box->nextRootBox()) |
| 348 nextRootBox->markDirty(); | 354 nextRootBox->markDirty(); |
| 349 } | 355 } |
| 350 } | 356 } |
| 351 | 357 |
| 352 #if ENABLE(ASSERT) | 358 #if ENABLE(ASSERT) |
| 353 void LineBoxList::checkConsistency() const { | 359 void LineBoxList::checkConsistency() const { |
| 354 #ifdef CHECK_CONSISTENCY | 360 #ifdef CHECK_CONSISTENCY |
| 355 const InlineFlowBox* prev = nullptr; | 361 const InlineFlowBox* prev = nullptr; |
| 356 for (const InlineFlowBox* child = m_firstLineBox; child; | 362 for (const InlineFlowBox* child = m_firstLineBox; child; |
| 357 child = child->nextLineBox()) { | 363 child = child->nextLineBox()) { |
| 358 ASSERT(child->prevLineBox() == prev); | 364 ASSERT(child->prevLineBox() == prev); |
| 359 prev = child; | 365 prev = child; |
| 360 } | 366 } |
| 361 ASSERT(prev == m_lastLineBox); | 367 ASSERT(prev == m_lastLineBox); |
| 362 #endif | 368 #endif |
| 363 } | 369 } |
| 364 | 370 |
| 365 #endif | 371 #endif |
| 366 | 372 |
| 367 } // namespace blink | 373 } // namespace blink |
| OLD | NEW |