Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 /* | 1 /* |
| 2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org) | 2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org) |
| 3 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights | 3 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights |
| 4 * reserved. | 4 * reserved. |
| 5 * | 5 * |
| 6 * This library is free software; you can redistribute it and/or | 6 * This library is free software; you can redistribute it and/or |
| 7 * modify it under the terms of the GNU Library General Public | 7 * modify it under the terms of the GNU Library General Public |
| 8 * License as published by the Free Software Foundation; either | 8 * License as published by the Free Software Foundation; either |
| 9 * version 2 of the License, or (at your option) any later version. | 9 * version 2 of the License, or (at your option) any later version. |
| 10 * | 10 * |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 21 | 21 |
| 22 #include "core/editing/LayoutSelection.h" | 22 #include "core/editing/LayoutSelection.h" |
| 23 | 23 |
| 24 #include "core/dom/Document.h" | 24 #include "core/dom/Document.h" |
| 25 #include "core/editing/EditingUtilities.h" | 25 #include "core/editing/EditingUtilities.h" |
| 26 #include "core/editing/FrameSelection.h" | 26 #include "core/editing/FrameSelection.h" |
| 27 #include "core/editing/VisiblePosition.h" | 27 #include "core/editing/VisiblePosition.h" |
| 28 #include "core/editing/VisibleUnits.h" | 28 #include "core/editing/VisibleUnits.h" |
| 29 #include "core/html/TextControlElement.h" | 29 #include "core/html/TextControlElement.h" |
| 30 #include "core/layout/LayoutView.h" | 30 #include "core/layout/LayoutView.h" |
| 31 #include "core/layout/ng/inline/ng_inline_items_builder.h" | |
| 32 #include "core/layout/ng/inline/ng_inline_node.h" | |
| 33 #include "core/layout/ng/inline/ng_inline_node_data.h" | |
| 34 #include "core/layout/ng/layout_ng_block_flow.h" | |
| 31 #include "core/paint/PaintLayer.h" | 35 #include "core/paint/PaintLayer.h" |
| 32 | 36 |
| 33 namespace blink { | 37 namespace blink { |
| 34 | 38 |
| 35 SelectionPaintRange::SelectionPaintRange(LayoutObject* start_layout_object, | 39 SelectionPaintRange::SelectionPaintRange(LayoutObject* start_layout_object, |
| 36 int start_offset, | 40 int start_offset, |
| 37 LayoutObject* end_layout_object, | 41 LayoutObject* end_layout_object, |
| 38 int end_offset) | 42 int end_offset) |
| 39 : start_layout_object_(start_layout_object), | 43 : start_layout_object_(start_layout_object), |
| 40 start_offset_(start_offset), | 44 start_offset_(start_offset), |
| 41 end_layout_object_(end_layout_object), | 45 end_layout_object_(end_layout_object), |
| 42 end_offset_(end_offset) { | 46 end_offset_(end_offset) { |
| 43 DCHECK(start_layout_object_); | 47 DCHECK(start_layout_object_); |
| 44 DCHECK(end_layout_object_); | 48 DCHECK(end_layout_object_); |
| 45 if (start_layout_object_ != end_layout_object_) | 49 if (start_layout_object_ != end_layout_object_) |
| 46 return; | 50 return; |
| 47 DCHECK_LT(start_offset_, end_offset_); | 51 DCHECK_LT(start_offset_, end_offset_); |
| 48 } | 52 } |
| 49 | 53 |
| 50 bool SelectionPaintRange::operator==(const SelectionPaintRange& other) const { | 54 bool SelectionPaintRange::operator==(const SelectionPaintRange& other) const { |
| 51 return start_layout_object_ == other.start_layout_object_ && | 55 return start_layout_object_ == other.start_layout_object_ && |
| 52 start_offset_ == other.start_offset_ && | 56 start_offset_ == other.start_offset_ && |
| 53 end_layout_object_ == other.end_layout_object_ && | 57 end_layout_object_ == other.end_layout_object_ && |
| 54 end_offset_ == other.end_offset_; | 58 end_offset_ == other.end_offset_; |
| 55 } | 59 } |
| 56 | 60 |
| 57 LayoutObject* SelectionPaintRange::StartLayoutObject() const { | 61 LayoutObject* SelectionPaintRange::StartLayoutObject() const { |
| 58 DCHECK(!IsNull()); | |
| 59 return start_layout_object_; | 62 return start_layout_object_; |
| 60 } | 63 } |
| 61 | 64 |
| 62 int SelectionPaintRange::StartOffset() const { | 65 int SelectionPaintRange::StartOffset() const { |
| 63 DCHECK(!IsNull()); | |
| 64 return start_offset_; | 66 return start_offset_; |
| 65 } | 67 } |
| 66 | 68 |
| 67 LayoutObject* SelectionPaintRange::EndLayoutObject() const { | 69 LayoutObject* SelectionPaintRange::EndLayoutObject() const { |
| 68 DCHECK(!IsNull()); | |
| 69 return end_layout_object_; | 70 return end_layout_object_; |
| 70 } | 71 } |
| 71 | 72 |
| 72 int SelectionPaintRange::EndOffset() const { | 73 int SelectionPaintRange::EndOffset() const { |
| 73 DCHECK(!IsNull()); | |
| 74 return end_offset_; | 74 return end_offset_; |
| 75 } | 75 } |
| 76 | 76 |
| 77 LayoutSelection::LayoutSelection(FrameSelection& frame_selection) | 77 LayoutSelection::LayoutSelection(FrameSelection& frame_selection) |
| 78 : frame_selection_(&frame_selection), | 78 : frame_selection_(&frame_selection), |
| 79 has_pending_selection_(false), | 79 has_pending_selection_(false), |
| 80 paint_range_(SelectionPaintRange()) {} | 80 paint_range_(nullptr) {} |
| 81 | 81 |
| 82 static SelectionInFlatTree CalcSelection( | 82 static SelectionInFlatTree CalcSelection( |
| 83 const VisibleSelectionInFlatTree& original_selection, | 83 const VisibleSelectionInFlatTree& original_selection, |
| 84 bool should_show_blok_cursor) { | 84 bool should_show_blok_cursor) { |
| 85 const PositionInFlatTree& start = original_selection.Start(); | 85 const PositionInFlatTree& start = original_selection.Start(); |
| 86 const PositionInFlatTree& end = original_selection.End(); | 86 const PositionInFlatTree& end = original_selection.End(); |
| 87 SelectionType selection_type = original_selection.GetSelectionType(); | 87 SelectionType selection_type = original_selection.GetSelectionType(); |
| 88 const TextAffinity affinity = original_selection.Affinity(); | 88 const TextAffinity affinity = original_selection.Affinity(); |
| 89 | 89 |
| 90 bool paint_block_cursor = | 90 bool paint_block_cursor = |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 163 DISALLOW_COPY_AND_ASSIGN(SelectedMap); | 163 DISALLOW_COPY_AND_ASSIGN(SelectedMap); |
| 164 }; | 164 }; |
| 165 | 165 |
| 166 enum class CollectSelectedMapOption { | 166 enum class CollectSelectedMapOption { |
| 167 kCollectBlock, | 167 kCollectBlock, |
| 168 kNotCollectBlock, | 168 kNotCollectBlock, |
| 169 }; | 169 }; |
| 170 | 170 |
| 171 static SelectedMap CollectSelectedMap(const SelectionPaintRange& range, | 171 static SelectedMap CollectSelectedMap(const SelectionPaintRange& range, |
| 172 CollectSelectedMapOption option) { | 172 CollectSelectedMapOption option) { |
| 173 if (range.IsNull()) | |
| 174 return SelectedMap(); | |
| 175 | |
| 176 SelectedMap selected_map; | 173 SelectedMap selected_map; |
| 177 | 174 |
| 178 LayoutObject* const stop = | 175 LayoutObject* const stop = |
| 179 LayoutObjectAfterPosition(range.EndLayoutObject(), range.EndOffset()); | 176 LayoutObjectAfterPosition(range.EndLayoutObject(), range.EndOffset()); |
| 180 for (LayoutObject* runner = range.StartLayoutObject(); | 177 for (LayoutObject* runner = range.StartLayoutObject(); |
| 181 runner && (runner != stop); runner = runner->NextInPreOrder()) { | 178 runner && (runner != stop); runner = runner->NextInPreOrder()) { |
| 182 if (!runner->CanBeSelectionLeaf() && runner != range.StartLayoutObject() && | 179 if (!runner->CanBeSelectionLeaf() && runner != range.StartLayoutObject() && |
| 183 runner != range.EndLayoutObject()) | 180 runner != range.EndLayoutObject()) |
| 184 continue; | 181 continue; |
| 185 if (runner->GetSelectionState() == SelectionState::kNone) | 182 if (runner->GetSelectionState() == SelectionState::kNone) |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 197 break; | 194 break; |
| 198 containing_block = containing_block->ContainingBlock(); | 195 containing_block = containing_block->ContainingBlock(); |
| 199 } | 196 } |
| 200 } | 197 } |
| 201 } | 198 } |
| 202 return selected_map; | 199 return selected_map; |
| 203 } | 200 } |
| 204 | 201 |
| 205 // Update the selection status of all LayoutObjects between |start| and |end|. | 202 // Update the selection status of all LayoutObjects between |start| and |end|. |
| 206 static void SetSelectionState(const SelectionPaintRange& range) { | 203 static void SetSelectionState(const SelectionPaintRange& range) { |
| 207 if (range.IsNull()) | |
| 208 return; | |
| 209 | |
| 210 if (range.StartLayoutObject() == range.EndLayoutObject()) { | 204 if (range.StartLayoutObject() == range.EndLayoutObject()) { |
| 211 range.StartLayoutObject()->SetSelectionStateIfNeeded( | 205 range.StartLayoutObject()->SetSelectionStateIfNeeded( |
| 212 SelectionState::kStartAndEnd); | 206 SelectionState::kStartAndEnd); |
| 213 } else { | 207 } else { |
| 214 range.StartLayoutObject()->SetSelectionStateIfNeeded( | 208 range.StartLayoutObject()->SetSelectionStateIfNeeded( |
| 215 SelectionState::kStart); | 209 SelectionState::kStart); |
| 216 range.EndLayoutObject()->SetSelectionStateIfNeeded(SelectionState::kEnd); | 210 range.EndLayoutObject()->SetSelectionStateIfNeeded(SelectionState::kEnd); |
| 217 } | 211 } |
| 218 | 212 |
| 219 LayoutObject* const stop = | 213 LayoutObject* const stop = |
| 220 LayoutObjectAfterPosition(range.EndLayoutObject(), range.EndOffset()); | 214 LayoutObjectAfterPosition(range.EndLayoutObject(), range.EndOffset()); |
| 221 for (LayoutObject* runner = range.StartLayoutObject(); | 215 for (LayoutObject* runner = range.StartLayoutObject(); |
| 222 runner && runner != stop; runner = runner->NextInPreOrder()) { | 216 runner && runner != stop; runner = runner->NextInPreOrder()) { |
| 223 if (runner != range.StartLayoutObject() && | 217 if (runner != range.StartLayoutObject() && |
| 224 runner != range.EndLayoutObject() && runner->CanBeSelectionLeaf()) | 218 runner != range.EndLayoutObject() && runner->CanBeSelectionLeaf()) |
| 225 runner->SetSelectionStateIfNeeded(SelectionState::kInside); | 219 runner->SetSelectionStateIfNeeded(SelectionState::kInside); |
| 226 } | 220 } |
| 227 } | 221 } |
| 228 | 222 |
| 229 // Set SetSelectionState and ShouldInvalidateSelection flag of LayoutObjects | 223 // Set SetSelectionState and ShouldInvalidateSelection flag of LayoutObjects |
| 230 // comparing them in |new_range| and |old_range|. | 224 // comparing them in |new_range| and |old_range|. |
| 231 static void UpdateLayoutObjectState(const SelectionPaintRange& new_range, | 225 static void UpdateLayoutObjectState(const SelectionPaintRange& new_range, |
| 232 const SelectionPaintRange& old_range) { | 226 const SelectionPaintRange* old_range) { |
| 233 SelectedMap old_selected_map = | 227 SelectedMap old_selected_map = |
| 234 CollectSelectedMap(old_range, CollectSelectedMapOption::kCollectBlock); | 228 old_range ? CollectSelectedMap(*old_range, |
| 229 CollectSelectedMapOption::kCollectBlock) | |
| 230 : SelectedMap(); | |
| 235 | 231 |
| 236 // Now clear the selection. | 232 // Now clear the selection. |
| 237 for (auto layout_object : old_selected_map.object_map.Keys()) | 233 for (auto layout_object : old_selected_map.object_map.Keys()) |
| 238 layout_object->SetSelectionStateIfNeeded(SelectionState::kNone); | 234 layout_object->SetSelectionStateIfNeeded(SelectionState::kNone); |
| 239 | 235 |
| 240 SetSelectionState(new_range); | 236 SetSelectionState(new_range); |
| 241 | 237 |
| 242 // Now that the selection state has been updated for the new objects, walk | 238 // Now that the selection state has been updated for the new objects, walk |
| 243 // them again and put them in the new objects list. | 239 // them again and put them in the new objects list. |
| 244 // TODO(editing-dev): |new_selected_map| doesn't really need to store the | 240 // TODO(editing-dev): |new_selected_map| doesn't really need to store the |
| 245 // SelectionState, it's just more convenient to have it use the same data | 241 // SelectionState, it's just more convenient to have it use the same data |
| 246 // structure as |old_selected_map|. | 242 // structure as |old_selected_map|. |
| 247 SelectedMap new_selected_map = | 243 SelectedMap new_selected_map = |
| 248 CollectSelectedMap(new_range, CollectSelectedMapOption::kCollectBlock); | 244 CollectSelectedMap(new_range, CollectSelectedMapOption::kCollectBlock); |
| 249 | 245 |
| 250 // Have any of the old selected objects changed compared to the new selection? | 246 // Have any of the old selected objects changed compared to the new selection? |
| 251 for (const auto& pair : old_selected_map.object_map) { | 247 for (const auto& pair : old_selected_map.object_map) { |
| 252 LayoutObject* obj = pair.key; | 248 LayoutObject* obj = pair.key; |
| 253 SelectionState new_selection_state = obj->GetSelectionState(); | 249 SelectionState new_selection_state = obj->GetSelectionState(); |
| 254 SelectionState old_selection_state = pair.value; | 250 SelectionState old_selection_state = pair.value; |
| 255 if (new_selection_state != old_selection_state || | 251 if (new_selection_state != old_selection_state || |
| 256 (new_range.StartLayoutObject() == obj && | 252 (new_range.StartLayoutObject() == obj && |
| 257 new_range.StartOffset() != old_range.StartOffset()) || | 253 new_range.StartOffset() != old_range->StartOffset()) || |
| 258 (new_range.EndLayoutObject() == obj && | 254 (new_range.EndLayoutObject() == obj && |
| 259 new_range.EndOffset() != old_range.EndOffset())) { | 255 new_range.EndOffset() != old_range->EndOffset())) { |
| 260 obj->SetShouldInvalidateSelection(); | 256 obj->SetShouldInvalidateSelection(); |
| 261 new_selected_map.object_map.erase(obj); | 257 new_selected_map.object_map.erase(obj); |
| 262 } | 258 } |
| 263 } | 259 } |
| 264 | 260 |
| 265 // Any new objects that remain were not found in the old objects dict, and so | 261 // Any new objects that remain were not found in the old objects dict, and so |
| 266 // they need to be updated. | 262 // they need to be updated. |
| 267 for (auto layout_object : new_selected_map.object_map.Keys()) | 263 for (auto layout_object : new_selected_map.object_map.Keys()) |
| 268 layout_object->SetShouldInvalidateSelection(); | 264 layout_object->SetShouldInvalidateSelection(); |
| 269 | 265 |
| 270 // Have any of the old blocks changed? | 266 // Have any of the old blocks changed? |
| 271 for (const auto& pair : old_selected_map.block_map) { | 267 for (const auto& pair : old_selected_map.block_map) { |
| 272 LayoutBlock* block = pair.key; | 268 LayoutBlock* block = pair.key; |
| 273 SelectionState new_selection_state = block->GetSelectionState(); | 269 SelectionState new_selection_state = block->GetSelectionState(); |
| 274 SelectionState old_selection_state = pair.value; | 270 SelectionState old_selection_state = pair.value; |
| 275 if (new_selection_state != old_selection_state) { | 271 if (new_selection_state != old_selection_state) { |
| 276 block->SetShouldInvalidateSelection(); | 272 block->SetShouldInvalidateSelection(); |
| 277 new_selected_map.block_map.erase(block); | 273 new_selected_map.block_map.erase(block); |
| 278 } | 274 } |
| 279 } | 275 } |
| 280 | 276 |
| 281 // Any new blocks that remain were not found in the old blocks dict, and so | 277 // Any new blocks that remain were not found in the old blocks dict, and so |
| 282 // they need to be updated. | 278 // they need to be updated. |
| 283 for (auto layout_object : new_selected_map.block_map.Keys()) | 279 for (auto layout_object : new_selected_map.block_map.Keys()) |
| 284 layout_object->SetShouldInvalidateSelection(); | 280 layout_object->SetShouldInvalidateSelection(); |
| 285 } | 281 } |
| 286 | 282 |
| 283 static LayoutBlockFlow* MostRecentLayoutBlockFlow(LayoutObject* layout_object) { | |
| 284 for (LayoutObject* runner = layout_object; runner && !runner->IsLayoutView(); | |
| 285 runner = runner->ContainingBlock()) { | |
|
kojii
2017/06/16 11:25:56
why ContainingBlock(), not Parent()?
yoichio
2017/06/21 08:16:43
Perhaps its my misunderstanding. If LayoutBlockFlo
| |
| 286 if (runner->IsLayoutBlockFlow()) | |
| 287 return ToLayoutBlockFlow(runner); | |
| 288 } | |
| 289 return nullptr; | |
| 290 } | |
| 291 | |
| 292 static int GetOffsetInMixedTree(Node* node, | |
| 293 LayoutObject* layout_object, | |
| 294 int offset) { | |
| 295 LayoutBlockFlow* start_block_flow = MostRecentLayoutBlockFlow(layout_object); | |
| 296 if (!start_block_flow || !start_block_flow->IsLayoutNGBlockFlow()) | |
| 297 return offset; // Legay. Return DOM offset; | |
|
yosin_UTC9
2017/06/16 02:04:20
nit: s/Legay/Legacy/
| |
| 298 | |
| 299 // TODO(yoichio): How about caching? Create takes | |
| 300 // O(<LayoutNGBlockflow.Data.text_content_>). | |
| 301 const NGTextOffsetMap& offset_map = | |
| 302 NGTextOffsetMap::Create(*ToLayoutNGBlockFlowOrDie(start_block_flow)); | |
| 303 const Optional<int> ng_offset = offset_map.Get(node, offset); | |
| 304 return ng_offset.value(); | |
| 305 } | |
| 306 | |
| 287 std::pair<int, int> LayoutSelection::SelectionStartEnd() { | 307 std::pair<int, int> LayoutSelection::SelectionStartEnd() { |
| 288 Commit(); | 308 Commit(); |
| 289 if (paint_range_.IsNull()) | 309 if (!paint_range_) |
| 290 return std::make_pair(-1, -1); | 310 return std::make_pair(-1, -1); |
| 291 return std::make_pair(paint_range_.StartOffset(), paint_range_.EndOffset()); | 311 if (!RuntimeEnabledFeatures::LayoutNGEnabled()) { |
| 312 return std::make_pair(paint_range_->StartOffset(), | |
| 313 paint_range_->EndOffset()); | |
| 314 } | |
| 315 // Layout NG mapping | |
| 316 const int start_offset_mixed = GetOffsetInMixedTree( | |
| 317 paint_range_->StartNode(), paint_range_->StartLayoutObject(), | |
| 318 paint_range_->StartOffset()); | |
| 319 const int end_offset_mixed = GetOffsetInMixedTree( | |
| 320 paint_range_->EndNode(), paint_range_->EndLayoutObject(), | |
| 321 paint_range_->EndOffset()); | |
| 322 return std::make_pair(start_offset_mixed, end_offset_mixed); | |
| 292 } | 323 } |
| 293 | 324 |
| 294 void LayoutSelection::ClearSelection() { | 325 void LayoutSelection::ClearSelection() { |
| 295 // For querying Layer::compositingState() | 326 // For querying Layer::compositingState() |
| 296 // This is correct, since destroying layout objects needs to cause eager paint | 327 // This is correct, since destroying layout objects needs to cause eager paint |
| 297 // invalidations. | 328 // invalidations. |
| 298 DisableCompositingQueryAsserts disabler; | 329 DisableCompositingQueryAsserts disabler; |
| 299 | 330 |
| 300 // Just return if the selection is already empty. | 331 // Just return if the selection is already empty. |
| 301 if (paint_range_.IsNull()) | 332 if (!paint_range_) |
| 302 return; | 333 return; |
| 303 | 334 |
| 304 const SelectedMap& old_selected_map = CollectSelectedMap( | 335 const SelectedMap& old_selected_map = CollectSelectedMap( |
| 305 paint_range_, CollectSelectedMapOption::kNotCollectBlock); | 336 *paint_range_, CollectSelectedMapOption::kNotCollectBlock); |
| 306 // Clear SelectionState and invalidation. | 337 // Clear SelectionState and invalidation. |
| 307 for (auto layout_object : old_selected_map.object_map.Keys()) { | 338 for (auto layout_object : old_selected_map.object_map.Keys()) { |
| 308 const SelectionState old_state = layout_object->GetSelectionState(); | 339 const SelectionState old_state = layout_object->GetSelectionState(); |
| 309 layout_object->SetSelectionStateIfNeeded(SelectionState::kNone); | 340 layout_object->SetSelectionStateIfNeeded(SelectionState::kNone); |
| 310 if (layout_object->GetSelectionState() == old_state) | 341 if (layout_object->GetSelectionState() == old_state) |
| 311 continue; | 342 continue; |
| 312 layout_object->SetShouldInvalidateSelection(); | 343 layout_object->SetShouldInvalidateSelection(); |
| 313 } | 344 } |
| 314 | 345 |
| 315 // Reset selection. | 346 // Reset selection. |
| 316 paint_range_ = SelectionPaintRange(); | 347 paint_range_ = nullptr; |
| 317 } | 348 } |
| 318 | 349 |
| 319 static SelectionPaintRange CalcSelectionPaintRange( | 350 static SelectionPaintRange* CalcSelectionNG( |
|
yosin_UTC9
2017/06/15 09:51:27
If this function traverse flat tree and works on l
yoichio
2017/06/21 08:16:42
I will rewrite w/o most.*CaretPosition() functions
| |
| 320 const FrameSelection& frame_selection) { | 351 const FrameSelection& frame_selection) { |
| 352 const SelectionInDOMTree& selection_in_dom = | |
| 353 frame_selection.GetSelectionInDOMTree(); | |
| 354 if (selection_in_dom.IsNone()) | |
| 355 return nullptr; | |
| 356 | |
| 357 // yoichio: Tthis should be on FlatTree. | |
| 358 const Position& start = selection_in_dom.ComputeStartPosition(); | |
|
yosin_UTC9
2017/06/15 09:39:02
Why don't you use flat tree version?
| |
| 359 const Position& end = selection_in_dom.ComputeEndPosition(); | |
| 360 LayoutObject* const start_layout_object = | |
|
yosin_UTC9
2017/06/16 02:04:20
|start_layout_object| can be nullptr.
So, we need
| |
| 361 start.AnchorNode()->GetLayoutObject(); | |
| 362 LayoutObject* const end_layout_object = end.AnchorNode()->GetLayoutObject(); | |
|
yosin_UTC9
2017/06/16 02:04:20
|end_layout_object_| can be nullptr.
So, we need t
| |
| 363 | |
| 364 Node* start_node = nullptr; | |
| 365 LayoutObject* paint_range_start = nullptr; | |
| 366 int paint_range_start_offset = -1; | |
| 367 // Seek the first text node. | |
| 368 for (LayoutObject* runner = start_layout_object; | |
| 369 runner && runner != end_layout_object->NextInPreOrder(); | |
| 370 runner = runner->NextInPreOrder()) { | |
| 371 if (runner->IsText() && runner->GetNode()->IsTextNode()) { | |
| 372 start_node = runner->GetNode(); | |
| 373 paint_range_start = runner; | |
| 374 if (runner == start_layout_object) { | |
| 375 paint_range_start_offset = start.ComputeEditingOffset(); | |
| 376 break; | |
| 377 } | |
| 378 paint_range_start_offset = 0; | |
| 379 break; | |
| 380 } | |
| 381 } | |
| 382 DCHECK(paint_range_start); | |
| 383 // Should consider block cursor painting. | |
| 384 Node* end_node = nullptr; | |
| 385 LayoutObject* paint_range_end = nullptr; | |
| 386 int paint_range_end_offset = -1; | |
| 387 for (LayoutObject* runner = end_layout_object; | |
| 388 runner && runner != start_layout_object->PreviousInPreOrder(); | |
| 389 runner = runner->PreviousInPreOrder()) { | |
| 390 if (runner->IsText() && runner->GetNode()->IsTextNode()) { | |
| 391 end_node = runner->GetNode(); | |
| 392 paint_range_end = runner; | |
| 393 if (runner == end_layout_object) { | |
| 394 paint_range_end_offset = end.ComputeEditingOffset(); | |
| 395 break; | |
| 396 } | |
| 397 LayoutText* text = ToLayoutText(runner); | |
| 398 paint_range_end_offset = text->TextLength(); | |
| 399 break; | |
| 400 } | |
| 401 } | |
| 402 DCHECK(paint_range_end); | |
| 403 | |
| 404 return new SelectionPaintRange(start_node, paint_range_start, | |
| 405 paint_range_start_offset, end_node, | |
| 406 paint_range_end, paint_range_end_offset); | |
| 407 } | |
| 408 // if(RuntimeEnabledFeatures::LayoutNGEnabled()) { | |
| 409 | |
| 410 static SelectionPaintRange* CalcSelectionPaintRange( | |
| 411 const FrameSelection& frame_selection) { | |
| 412 if (RuntimeEnabledFeatures::LayoutNGEnabled()) | |
| 413 return CalcSelectionNG(frame_selection); | |
|
yosin_UTC9
2017/06/15 09:39:02
So, for painting selection, we need to have NG ver
| |
| 414 | |
| 415 // NGMemo: ComputeVisibleSelectionInFlatTree depends on offsetmapping from | |
| 416 // DOM->NG. | |
| 321 const VisibleSelectionInFlatTree& original_selection = | 417 const VisibleSelectionInFlatTree& original_selection = |
| 322 frame_selection.ComputeVisibleSelectionInFlatTree(); | 418 frame_selection.ComputeVisibleSelectionInFlatTree(); |
| 323 // Construct a new VisibleSolution, since visibleSelection() is not | 419 // Construct a new VisibleSolution, since visibleSelection() is not |
| 324 // necessarily valid, and the following steps assume a valid selection. See | 420 // necessarily valid, and the following steps assume a valid selection. See |
| 325 // <https://bugs.webkit.org/show_bug.cgi?id=69563> and | 421 // <https://bugs.webkit.org/show_bug.cgi?id=69563> and |
| 326 // <rdar://problem/10232866>. | 422 // <rdar://problem/10232866>. |
| 327 const SelectionInFlatTree& new_selection = CalcSelection( | 423 const SelectionInFlatTree& new_selection = CalcSelection( |
| 328 original_selection, frame_selection.ShouldShowBlockCursor()); | 424 original_selection, frame_selection.ShouldShowBlockCursor()); |
| 329 const VisibleSelectionInFlatTree& selection = | 425 const VisibleSelectionInFlatTree& selection = |
| 330 CreateVisibleSelection(new_selection); | 426 CreateVisibleSelection(new_selection); |
| 331 | 427 |
| 332 if (!selection.IsRange() || frame_selection.IsHidden()) | 428 if (!selection.IsRange() || frame_selection.IsHidden()) |
| 333 return SelectionPaintRange(); | 429 return nullptr; |
| 334 | 430 |
| 335 DCHECK(!selection.IsNone()); | 431 DCHECK(!selection.IsNone()); |
| 336 // Use the rightmost candidate for the start of the selection, and the | 432 // Use the rightmost candidate for the start of the selection, and the |
| 337 // leftmost candidate for the end of the selection. Example: foo <a>bar</a>. | 433 // leftmost candidate for the end of the selection. Example: foo <a>bar</a>. |
| 338 // Imagine that a line wrap occurs after 'foo', and that 'bar' is selected. | 434 // Imagine that a line wrap occurs after 'foo', and that 'bar' is selected. |
| 339 // If we pass [foo, 3] as the start of the selection, the selection painting | 435 // If we pass [foo, 3] as the start of the selection, the selection painting |
| 340 // code will think that content on the line containing 'foo' is selected | 436 // code will think that content on the line containing 'foo' is selected |
| 341 // and will fill the gap before 'bar'. | 437 // and will fill the gap before 'bar'. |
| 342 PositionInFlatTree start_pos = selection.Start(); | 438 PositionInFlatTree start_pos = selection.Start(); |
| 343 const PositionInFlatTree most_forward_start = | 439 const PositionInFlatTree most_forward_start = |
| 344 MostForwardCaretPosition(start_pos); | 440 MostForwardCaretPosition(start_pos); |
| 345 if (IsVisuallyEquivalentCandidate(most_forward_start)) | 441 if (IsVisuallyEquivalentCandidate(most_forward_start)) |
| 346 start_pos = most_forward_start; | 442 start_pos = most_forward_start; |
| 347 PositionInFlatTree end_pos = selection.End(); | 443 PositionInFlatTree end_pos = selection.End(); |
| 348 const PositionInFlatTree most_backward = MostBackwardCaretPosition(end_pos); | 444 const PositionInFlatTree most_backward = MostBackwardCaretPosition(end_pos); |
| 349 if (IsVisuallyEquivalentCandidate(most_backward)) | 445 if (IsVisuallyEquivalentCandidate(most_backward)) |
| 350 end_pos = most_backward; | 446 end_pos = most_backward; |
| 351 | 447 |
| 352 DCHECK(start_pos.IsNotNull()); | 448 DCHECK(start_pos.IsNotNull()); |
| 353 DCHECK(end_pos.IsNotNull()); | 449 DCHECK(end_pos.IsNotNull()); |
| 354 DCHECK_LE(start_pos, end_pos); | 450 DCHECK_LE(start_pos, end_pos); |
| 355 LayoutObject* start_layout_object = start_pos.AnchorNode()->GetLayoutObject(); | 451 LayoutObject* start_layout_object = start_pos.AnchorNode()->GetLayoutObject(); |
| 356 LayoutObject* end_layout_object = end_pos.AnchorNode()->GetLayoutObject(); | 452 LayoutObject* end_layout_object = end_pos.AnchorNode()->GetLayoutObject(); |
| 357 DCHECK(start_layout_object); | 453 DCHECK(start_layout_object); |
| 358 DCHECK(end_layout_object); | 454 DCHECK(end_layout_object); |
| 359 DCHECK(start_layout_object->View() == end_layout_object->View()); | 455 DCHECK(start_layout_object->View() == end_layout_object->View()); |
| 360 | 456 |
| 361 return SelectionPaintRange(start_layout_object, | 457 return new SelectionPaintRange( |
| 362 start_pos.ComputeEditingOffset(), | 458 start_layout_object, start_pos.ComputeEditingOffset(), end_layout_object, |
| 363 end_layout_object, end_pos.ComputeEditingOffset()); | 459 end_pos.ComputeEditingOffset()); |
| 364 } | 460 } |
| 365 | 461 |
| 366 void LayoutSelection::Commit() { | 462 void LayoutSelection::Commit() { |
| 367 if (!HasPendingSelection()) | 463 if (!HasPendingSelection()) |
| 368 return; | 464 return; |
| 369 has_pending_selection_ = false; | 465 has_pending_selection_ = false; |
| 370 | 466 |
| 371 const SelectionPaintRange& new_range = | 467 SelectionPaintRange* new_range = CalcSelectionPaintRange(*frame_selection_); |
| 372 CalcSelectionPaintRange(*frame_selection_); | 468 if (!new_range) { |
| 373 if (new_range.IsNull()) { | |
| 374 ClearSelection(); | 469 ClearSelection(); |
| 375 return; | 470 return; |
| 376 } | 471 } |
| 377 // Just return if the selection hasn't changed. | 472 // Just return if the selection hasn't changed. |
| 378 if (paint_range_ == new_range) | 473 if (paint_range_ && *paint_range_ == *new_range) |
| 379 return; | 474 return; |
| 380 | 475 |
| 381 DCHECK(frame_selection_->GetDocument().GetLayoutView()->GetFrameView()); | 476 DCHECK(frame_selection_->GetDocument().GetLayoutView()->GetFrameView()); |
| 382 DCHECK(!frame_selection_->GetDocument().NeedsLayoutTreeUpdate()); | 477 DCHECK(!frame_selection_->GetDocument().NeedsLayoutTreeUpdate()); |
| 383 UpdateLayoutObjectState(new_range, paint_range_); | 478 UpdateLayoutObjectState(*new_range, paint_range_); |
| 384 paint_range_ = new_range; | 479 paint_range_ = new_range; |
| 385 } | 480 } |
| 386 | 481 |
| 387 void LayoutSelection::OnDocumentShutdown() { | 482 void LayoutSelection::OnDocumentShutdown() { |
| 388 has_pending_selection_ = false; | 483 has_pending_selection_ = false; |
| 389 paint_range_ = SelectionPaintRange(); | 484 paint_range_ = nullptr; |
| 390 } | 485 } |
| 391 | 486 |
| 392 static LayoutRect SelectionRectForLayoutObject(const LayoutObject* object) { | 487 static LayoutRect SelectionRectForLayoutObject(const LayoutObject* object) { |
| 393 if (!object->IsRooted()) | 488 if (!object->IsRooted()) |
| 394 return LayoutRect(); | 489 return LayoutRect(); |
| 395 | 490 |
| 396 if (!object->CanUpdateSelectionOnRootLineBoxes()) | 491 if (!object->CanUpdateSelectionOnRootLineBoxes()) |
| 397 return LayoutRect(); | 492 return LayoutRect(); |
| 398 | 493 |
| 399 return object->SelectionRectInViewCoordinates(); | 494 return object->SelectionRectInViewCoordinates(); |
| 400 } | 495 } |
| 401 | 496 |
| 402 IntRect LayoutSelection::SelectionBounds() { | 497 IntRect LayoutSelection::SelectionBounds() { |
| 403 // Now create a single bounding box rect that encloses the whole selection. | 498 // Now create a single bounding box rect that encloses the whole selection. |
| 404 LayoutRect sel_rect; | 499 LayoutRect sel_rect; |
| 405 | 500 |
| 406 typedef HashSet<const LayoutBlock*> VisitedContainingBlockSet; | 501 typedef HashSet<const LayoutBlock*> VisitedContainingBlockSet; |
| 407 VisitedContainingBlockSet visited_containing_blocks; | 502 VisitedContainingBlockSet visited_containing_blocks; |
| 408 | 503 |
| 409 Commit(); | 504 Commit(); |
| 410 if (paint_range_.IsNull()) | 505 if (!paint_range_) |
| 411 return IntRect(); | 506 return IntRect(); |
| 412 | 507 |
| 413 LayoutObject* os = paint_range_.StartLayoutObject(); | 508 LayoutObject* os = paint_range_->StartLayoutObject(); |
| 414 LayoutObject* stop = LayoutObjectAfterPosition(paint_range_.EndLayoutObject(), | 509 LayoutObject* stop = LayoutObjectAfterPosition( |
| 415 paint_range_.EndOffset()); | 510 paint_range_->EndLayoutObject(), paint_range_->EndOffset()); |
| 416 while (os && os != stop) { | 511 while (os && os != stop) { |
| 417 if ((os->CanBeSelectionLeaf() || os == paint_range_.StartLayoutObject() || | 512 if ((os->CanBeSelectionLeaf() || os == paint_range_->StartLayoutObject() || |
| 418 os == paint_range_.EndLayoutObject()) && | 513 os == paint_range_->EndLayoutObject()) && |
| 419 os->GetSelectionState() != SelectionState::kNone) { | 514 os->GetSelectionState() != SelectionState::kNone) { |
| 420 // Blocks are responsible for painting line gaps and margin gaps. They | 515 // Blocks are responsible for painting line gaps and margin gaps. They |
| 421 // must be examined as well. | 516 // must be examined as well. |
| 422 sel_rect.Unite(SelectionRectForLayoutObject(os)); | 517 sel_rect.Unite(SelectionRectForLayoutObject(os)); |
| 423 const LayoutBlock* cb = os->ContainingBlock(); | 518 const LayoutBlock* cb = os->ContainingBlock(); |
| 424 while (cb && !cb->IsLayoutView()) { | 519 while (cb && !cb->IsLayoutView()) { |
| 425 sel_rect.Unite(SelectionRectForLayoutObject(cb)); | 520 sel_rect.Unite(SelectionRectForLayoutObject(cb)); |
| 426 VisitedContainingBlockSet::AddResult add_result = | 521 VisitedContainingBlockSet::AddResult add_result = |
| 427 visited_containing_blocks.insert(cb); | 522 visited_containing_blocks.insert(cb); |
| 428 if (!add_result.is_new_entry) | 523 if (!add_result.is_new_entry) |
| 429 break; | 524 break; |
| 430 cb = cb->ContainingBlock(); | 525 cb = cb->ContainingBlock(); |
| 431 } | 526 } |
| 432 } | 527 } |
| 433 | 528 |
| 434 os = os->NextInPreOrder(); | 529 os = os->NextInPreOrder(); |
| 435 } | 530 } |
| 436 | 531 |
| 437 return PixelSnappedIntRect(sel_rect); | 532 return PixelSnappedIntRect(sel_rect); |
| 438 } | 533 } |
| 439 | 534 |
| 440 void LayoutSelection::InvalidatePaintForSelection() { | 535 void LayoutSelection::InvalidatePaintForSelection() { |
| 441 if (paint_range_.IsNull()) | 536 if (!paint_range_) |
| 442 return; | 537 return; |
| 443 | 538 |
| 444 LayoutObject* end = LayoutObjectAfterPosition(paint_range_.EndLayoutObject(), | 539 LayoutObject* end = LayoutObjectAfterPosition(paint_range_->EndLayoutObject(), |
| 445 paint_range_.EndOffset()); | 540 paint_range_->EndOffset()); |
| 446 for (LayoutObject* o = paint_range_.StartLayoutObject(); o && o != end; | 541 for (LayoutObject* o = paint_range_->StartLayoutObject(); o && o != end; |
| 447 o = o->NextInPreOrder()) { | 542 o = o->NextInPreOrder()) { |
| 448 if (!o->CanBeSelectionLeaf() && o != paint_range_.StartLayoutObject() && | 543 if (!o->CanBeSelectionLeaf() && o != paint_range_->StartLayoutObject() && |
| 449 o != paint_range_.EndLayoutObject()) | 544 o != paint_range_->EndLayoutObject()) |
| 450 continue; | 545 continue; |
| 451 if (o->GetSelectionState() == SelectionState::kNone) | 546 if (o->GetSelectionState() == SelectionState::kNone) |
| 452 continue; | 547 continue; |
| 453 | 548 |
| 454 o->SetShouldInvalidateSelection(); | 549 o->SetShouldInvalidateSelection(); |
| 455 } | 550 } |
| 456 } | 551 } |
| 457 | 552 |
| 458 DEFINE_TRACE(LayoutSelection) { | 553 DEFINE_TRACE(LayoutSelection) { |
| 459 visitor->Trace(frame_selection_); | 554 visitor->Trace(frame_selection_); |
| 555 visitor->Trace(paint_range_); | |
| 556 } | |
| 557 | |
| 558 NGTextOffsetMap::Builder::Builder() : offset_map_(new NGTextOffsetMap) {} | |
|
kojii
2017/06/16 11:25:56
so this part will be removed and not for review, c
| |
| 559 | |
| 560 void NGTextOffsetMap::Builder::Add(Node* node, | |
| 561 int dom_offset, | |
| 562 int layout_offset) { | |
| 563 DCHECK(node); | |
| 564 offset_map_->node_to_offset_map_.Set(std::make_pair(node, dom_offset), | |
| 565 layout_offset); | |
| 566 } | |
| 567 | |
| 568 NGTextOffsetMap NGTextOffsetMap::Builder::Build() { | |
| 569 return std::move(*offset_map_); | |
| 570 } | |
| 571 | |
| 572 Optional<int> NGTextOffsetMap::Get(Node* node, int dom_offset) const { | |
| 573 if (!node) | |
| 574 return Optional<int>(); | |
| 575 auto iterator = node_to_offset_map_.find(std::make_pair(node, dom_offset)); | |
| 576 if (iterator == node_to_offset_map_.end()) | |
| 577 return Optional<int>(); | |
| 578 return iterator->value; | |
| 579 } | |
| 580 | |
| 581 NGTextOffsetMap NGTextOffsetMap::Create( | |
| 582 const LayoutNGBlockFlow& ng_block_flow) { | |
| 583 NGTextOffsetMap::Builder builder; | |
| 584 Vector<NGInlineItem> pseudo_items; | |
| 585 Vector<int> offset_mapping; | |
| 586 offset_mapping.push_back(0); | |
| 587 NGInlineItemsBuilder items_builder(&pseudo_items, &offset_mapping); | |
| 588 | |
| 589 LayoutObject* last_object = nullptr; | |
| 590 for (const auto& item : ng_block_flow.GetNGInlineNodeData().items_) { | |
| 591 LayoutObject* layout_object = item.GetLayoutObject(); | |
| 592 if (!layout_object || !layout_object->IsText() || | |
| 593 layout_object == last_object) | |
| 594 continue; | |
| 595 | |
| 596 Text* text = ToText(layout_object->GetNode()); | |
| 597 size_t begin = offset_mapping.size(); | |
| 598 items_builder.Append(text->textContent(), layout_object->Style(), | |
| 599 layout_object); | |
| 600 size_t end = offset_mapping.size(); | |
| 601 for (size_t i = 0; i < end - begin + 1; i++) { | |
| 602 int ng_offset = offset_mapping[begin + i - 1]; | |
| 603 builder.Add(text, i, ng_offset); | |
| 604 } | |
| 605 | |
| 606 last_object = layout_object; | |
| 607 } | |
| 608 return builder.Build(); | |
| 460 } | 609 } |
| 461 | 610 |
| 462 } // namespace blink | 611 } // namespace blink |
| OLD | NEW |