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 |