| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (C) 2004, 2005, 2006, 2007 Apple Inc. All rights reserved. | 2 * Copyright (C) 2004, 2005, 2006, 2007 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 * 1. Redistributions of source code must retain the above copyright | 7 * 1. Redistributions of source code must retain the above copyright |
| 8 * notice, this list of conditions and the following disclaimer. | 8 * notice, this list of conditions and the following disclaimer. |
| 9 * 2. Redistributions in binary form must reproduce the above copyright | 9 * 2. Redistributions in binary form must reproduce the above copyright |
| 10 * notice, this list of conditions and the following disclaimer in the | 10 * notice, this list of conditions and the following disclaimer in the |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 58 #include <wtf/unicode/CharacterNames.h> | 58 #include <wtf/unicode/CharacterNames.h> |
| 59 | 59 |
| 60 using namespace std; | 60 using namespace std; |
| 61 | 61 |
| 62 namespace WebCore { | 62 namespace WebCore { |
| 63 | 63 |
| 64 using namespace HTMLNames; | 64 using namespace HTMLNames; |
| 65 | 65 |
| 66 // Atomic means that the node has no children, or has children which are ignored
for the | 66 // Atomic means that the node has no children, or has children which are ignored
for the |
| 67 // purposes of editing. | 67 // purposes of editing. |
| 68 bool isAtomicNode(const Node *node) | 68 bool isAtomicNode(const Handle<const Node>& node) |
| 69 { | 69 { |
| 70 return node && (!node->hasChildNodes() || editingIgnoresContent(node)); | 70 return node && (!node->hasChildNodes() || editingIgnoresContent(node)); |
| 71 } | 71 } |
| 72 | 72 |
| 73 // Compare two positions, taking into account the possibility that one or both | 73 // Compare two positions, taking into account the possibility that one or both |
| 74 // could be inside a shadow tree. Only works for non-null values. | 74 // could be inside a shadow tree. Only works for non-null values. |
| 75 int comparePositions(const Position& a, const Position& b) | 75 int comparePositions(const Position& a, const Position& b) |
| 76 { | 76 { |
| 77 Handle<TreeScope> commonScope = commonTreeScope(a.containerNode().handle().r
aw(), b.containerNode().handle().raw()); | 77 Handle<TreeScope> commonScope = commonTreeScope(a.containerNode().handle().r
aw(), b.containerNode().handle().raw()); |
| 78 | 78 |
| (...skipping 21 matching lines...) Expand all Loading... |
| 100 | 100 |
| 101 int result = Range::compareBoundaryPoints(adoptRawResult(nodeA), offsetA, ad
optRawResult(nodeB), offsetB, IGNORE_EXCEPTION); | 101 int result = Range::compareBoundaryPoints(adoptRawResult(nodeA), offsetA, ad
optRawResult(nodeB), offsetB, IGNORE_EXCEPTION); |
| 102 return result ? result : bias; | 102 return result ? result : bias; |
| 103 } | 103 } |
| 104 | 104 |
| 105 int comparePositions(const VisiblePosition& a, const VisiblePosition& b) | 105 int comparePositions(const VisiblePosition& a, const VisiblePosition& b) |
| 106 { | 106 { |
| 107 return comparePositions(a.deepEquivalent(), b.deepEquivalent()); | 107 return comparePositions(a.deepEquivalent(), b.deepEquivalent()); |
| 108 } | 108 } |
| 109 | 109 |
| 110 Node* highestEditableRoot(const Position& position, EditableType editableType) | 110 Result<Node> highestEditableRoot(const Position& position, EditableType editable
Type) |
| 111 { | 111 { |
| 112 Handle<Node> node = position.deprecatedNode(); | 112 Handle<Node> node = position.deprecatedNode(); |
| 113 if (!node) | 113 if (!node) |
| 114 return 0; | 114 return nullptr; |
| 115 | 115 |
| 116 Handle<Node> highestRoot = editableRootForPosition(position, editableType); | 116 Handle<Node> highestRoot = editableRootForPosition(position, editableType); |
| 117 if (!highestRoot) | 117 if (!highestRoot) |
| 118 return 0; | 118 return nullptr; |
| 119 | 119 |
| 120 node = highestRoot; | 120 node = highestRoot; |
| 121 while (node) { | 121 while (node) { |
| 122 HandleScope scope; | 122 HandleScope scope; |
| 123 if (node->rendererIsEditable(editableType)) | 123 if (node->rendererIsEditable(editableType)) |
| 124 highestRoot = node; | 124 highestRoot = node; |
| 125 if (node->hasTagName(bodyTag)) | 125 if (node->hasTagName(bodyTag)) |
| 126 break; | 126 break; |
| 127 node = node->parentNode(); | 127 node = node->parentNode(); |
| 128 } | 128 } |
| 129 | 129 |
| 130 return highestRoot.raw(); | 130 return highestRoot; |
| 131 } | 131 } |
| 132 | 132 |
| 133 Node* lowestEditableAncestor(Node* node) | 133 Result<Node> lowestEditableAncestor(const Handle<Node>& node) |
| 134 { | 134 { |
| 135 if (!node) | 135 if (!node) |
| 136 return 0; | 136 return nullptr; |
| 137 | 137 |
| 138 Node* lowestRoot = 0; | 138 Handle<Node> lowestRoot; |
| 139 Handle<Node> current = adoptRawResult(node); | 139 Handle<Node> current = node; |
| 140 while (current) { | 140 while (current) { |
| 141 HandleScope scope; | 141 HandleScope scope; |
| 142 if (current->rendererIsEditable()) | 142 if (current->rendererIsEditable()) |
| 143 return current->rootEditableElement().handle().raw(); | 143 return current->rootEditableElement(); |
| 144 if (current->hasTagName(bodyTag)) | 144 if (current->hasTagName(bodyTag)) |
| 145 break; | 145 break; |
| 146 current = current->parentNode(); | 146 current = current->parentNode(); |
| 147 } | 147 } |
| 148 | 148 |
| 149 return lowestRoot; | 149 return lowestRoot; |
| 150 } | 150 } |
| 151 | 151 |
| 152 bool isEditablePosition(const Position& p, EditableType editableType, EUpdateSty
le updateStyle) | 152 bool isEditablePosition(const Position& p, EditableType editableType, EUpdateSty
le updateStyle) |
| 153 { | 153 { |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 196 return node->rootEditableElement(editableType); | 196 return node->rootEditableElement(editableType); |
| 197 } | 197 } |
| 198 | 198 |
| 199 // Finds the enclosing element until which the tree can be split. | 199 // Finds the enclosing element until which the tree can be split. |
| 200 // When a user hits ENTER, he/she won't expect this element to be split into two
. | 200 // When a user hits ENTER, he/she won't expect this element to be split into two
. |
| 201 // You may pass it as the second argument of splitTreeToNode. | 201 // You may pass it as the second argument of splitTreeToNode. |
| 202 Result<Element> unsplittableElementForPosition(const Position& p) | 202 Result<Element> unsplittableElementForPosition(const Position& p) |
| 203 { | 203 { |
| 204 // Since enclosingNodeOfType won't search beyond the highest root editable n
ode, | 204 // Since enclosingNodeOfType won't search beyond the highest root editable n
ode, |
| 205 // this code works even if the closest table cell was outside of the root ed
itable node. | 205 // this code works even if the closest table cell was outside of the root ed
itable node. |
| 206 Handle<Element> enclosingCell = adoptRawResult(toElement(enclosingNodeOfType
(p, &isTableCell))); | 206 Handle<Element> enclosingCell = toElement(enclosingNodeOfType(p, &isTableCel
l)); |
| 207 if (enclosingCell) | 207 if (enclosingCell) |
| 208 return enclosingCell; | 208 return enclosingCell; |
| 209 | 209 |
| 210 return editableRootForPosition(p); | 210 return editableRootForPosition(p); |
| 211 } | 211 } |
| 212 | 212 |
| 213 Position nextCandidate(const Position& position) | 213 Position nextCandidate(const Position& position) |
| 214 { | 214 { |
| 215 PositionIterator p = position; | 215 PositionIterator p = position; |
| 216 while (!p.atEnd()) { | 216 while (!p.atEnd()) { |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 253 Position downstreamStart = p.downstream(); | 253 Position downstreamStart = p.downstream(); |
| 254 while (!p.atStartOfTree()) { | 254 while (!p.atStartOfTree()) { |
| 255 HandleScope scope; | 255 HandleScope scope; |
| 256 p = p.previous(Character); | 256 p = p.previous(Character); |
| 257 if (p.isCandidate() && p.downstream() != downstreamStart) | 257 if (p.isCandidate() && p.downstream() != downstreamStart) |
| 258 return p; | 258 return p; |
| 259 } | 259 } |
| 260 return Position(); | 260 return Position(); |
| 261 } | 261 } |
| 262 | 262 |
| 263 VisiblePosition firstEditablePositionAfterPositionInRoot(const Position& positio
n, Node* highestRoot) | 263 VisiblePosition firstEditablePositionAfterPositionInRoot(const Position& positio
n, const Handle<Node>& highestRoot) |
| 264 { | 264 { |
| 265 // position falls before highestRoot. | 265 // position falls before highestRoot. |
| 266 if (comparePositions(position, firstPositionInNode(adoptRawResult(highestRoo
t))) == -1 && highestRoot->rendererIsEditable()) | 266 if (comparePositions(position, firstPositionInNode(highestRoot)) == -1 && hi
ghestRoot->rendererIsEditable()) |
| 267 return firstPositionInNode(adoptRawResult(highestRoot)); | 267 return firstPositionInNode(highestRoot); |
| 268 | 268 |
| 269 Position p = position; | 269 Position p = position; |
| 270 | 270 |
| 271 if (position.deprecatedNode()->treeScope() != highestRoot->treeScope()) { | 271 if (position.deprecatedNode()->treeScope() != highestRoot->treeScope()) { |
| 272 Handle<Node> shadowAncestor = adoptRawResult(highestRoot->treeScope()->a
ncestorInThisScope(p.deprecatedNode().handle().raw())); | 272 Handle<Node> shadowAncestor = adoptRawResult(highestRoot->treeScope()->a
ncestorInThisScope(p.deprecatedNode().handle().raw())); |
| 273 if (!shadowAncestor) | 273 if (!shadowAncestor) |
| 274 return VisiblePosition(); | 274 return VisiblePosition(); |
| 275 | 275 |
| 276 p = positionAfterNode(shadowAncestor); | 276 p = positionAfterNode(shadowAncestor); |
| 277 } | 277 } |
| 278 | 278 |
| 279 while (p.deprecatedNode() && !isEditablePosition(p) && p.deprecatedNode()->i
sDescendantOf(highestRoot)) { | 279 while (p.deprecatedNode() && !isEditablePosition(p) && p.deprecatedNode()->i
sDescendantOf(highestRoot.raw())) { |
| 280 HandleScope scope; | 280 HandleScope scope; |
| 281 p = isAtomicNode(p.deprecatedNode().handle().raw()) ? positionInParentAf
terNode(p.deprecatedNode()) : nextVisuallyDistinctCandidate(p); | 281 p = isAtomicNode(p.deprecatedNode()) ? positionInParentAfterNode(p.depre
catedNode()) : nextVisuallyDistinctCandidate(p); |
| 282 } | 282 } |
| 283 | 283 |
| 284 if (p.deprecatedNode() && p.deprecatedNode() != highestRoot && !p.deprecated
Node()->isDescendantOf(highestRoot)) | 284 if (p.deprecatedNode() && p.deprecatedNode() != highestRoot && !p.deprecated
Node()->isDescendantOf(highestRoot.raw())) |
| 285 return VisiblePosition(); | 285 return VisiblePosition(); |
| 286 | 286 |
| 287 return VisiblePosition(p); | 287 return VisiblePosition(p); |
| 288 } | 288 } |
| 289 | 289 |
| 290 VisiblePosition lastEditablePositionBeforePositionInRoot(const Position& positio
n, Node* highestRoot) | 290 VisiblePosition lastEditablePositionBeforePositionInRoot(const Position& positio
n, const Handle<Node>& highestRoot) |
| 291 { | 291 { |
| 292 // When position falls after highestRoot, the result is easy to compute. | 292 // When position falls after highestRoot, the result is easy to compute. |
| 293 if (comparePositions(position, lastPositionInNode(adoptRawResult(highestRoot
))) == 1) | 293 if (comparePositions(position, lastPositionInNode(highestRoot)) == 1) |
| 294 return lastPositionInNode(adoptRawResult(highestRoot)); | 294 return lastPositionInNode(highestRoot); |
| 295 | 295 |
| 296 Position p = position; | 296 Position p = position; |
| 297 | 297 |
| 298 if (position.deprecatedNode()->treeScope() != highestRoot->treeScope()) { | 298 if (position.deprecatedNode()->treeScope() != highestRoot->treeScope()) { |
| 299 Node* shadowAncestor = highestRoot->treeScope()->ancestorInThisScope(p.d
eprecatedNode().handle().raw()); | 299 Handle<Node> shadowAncestor = adoptRawResult(highestRoot->treeScope()->a
ncestorInThisScope(p.deprecatedNode().handle().raw())); |
| 300 if (!shadowAncestor) | 300 if (!shadowAncestor) |
| 301 return VisiblePosition(); | 301 return VisiblePosition(); |
| 302 | 302 |
| 303 p = firstPositionInOrBeforeNode(shadowAncestor); | 303 p = firstPositionInOrBeforeNode(shadowAncestor); |
| 304 } | 304 } |
| 305 | 305 |
| 306 while (p.deprecatedNode() && !isEditablePosition(p) && p.deprecatedNode()->i
sDescendantOf(highestRoot)) { | 306 while (p.deprecatedNode() && !isEditablePosition(p) && p.deprecatedNode()->i
sDescendantOf(highestRoot.raw())) { |
| 307 HandleScope scope; | 307 HandleScope scope; |
| 308 p = isAtomicNode(p.deprecatedNode().handle().raw()) ? positionInParentBe
foreNode(p.deprecatedNode()) : previousVisuallyDistinctCandidate(p); | 308 p = isAtomicNode(p.deprecatedNode()) ? positionInParentBeforeNode(p.depr
ecatedNode()) : previousVisuallyDistinctCandidate(p); |
| 309 } | 309 } |
| 310 | 310 |
| 311 if (p.deprecatedNode() && p.deprecatedNode() != highestRoot && !p.deprecated
Node()->isDescendantOf(highestRoot)) | 311 if (p.deprecatedNode() && p.deprecatedNode() != highestRoot && !p.deprecated
Node()->isDescendantOf(highestRoot.raw())) |
| 312 return VisiblePosition(); | 312 return VisiblePosition(); |
| 313 | 313 |
| 314 return VisiblePosition(p); | 314 return VisiblePosition(p); |
| 315 } | 315 } |
| 316 | 316 |
| 317 // FIXME: The method name, comment, and code say three different things here! | 317 // FIXME: The method name, comment, and code say three different things here! |
| 318 // Whether or not content before and after this node will collapse onto the same
line as it. | 318 // Whether or not content before and after this node will collapse onto the same
line as it. |
| 319 bool isBlock(const Node* node) | 319 bool isBlock(const Handle<const Node>& node) |
| 320 { | 320 { |
| 321 return node && node->renderer() && !node->renderer()->isInline() && !node->r
enderer()->isRubyText(); | 321 return node && node->renderer() && !node->renderer()->isInline() && !node->r
enderer()->isRubyText(); |
| 322 } | 322 } |
| 323 | 323 |
| 324 bool isInline(const Node* node) | 324 bool isInline(const Handle<const Node>& node) |
| 325 { | 325 { |
| 326 return node && node->renderer() && node->renderer()->isInline(); | 326 return node && node->renderer() && node->renderer()->isInline(); |
| 327 } | 327 } |
| 328 | 328 |
| 329 // FIXME: Deploy this in all of the places where enclosingBlockFlow/enclosingBlo
ckFlowOrTableElement are used. | 329 // FIXME: Deploy this in all of the places where enclosingBlockFlow/enclosingBlo
ckFlowOrTableElement are used. |
| 330 // FIXME: Pass a position to this function. The enclosing block of [table, x] fo
r example, should be the | 330 // FIXME: Pass a position to this function. The enclosing block of [table, x] fo
r example, should be the |
| 331 // block that contains the table and not the table, and this function should be
the only one responsible for | 331 // block that contains the table and not the table, and this function should be
the only one responsible for |
| 332 // knowing about these kinds of special cases. | 332 // knowing about these kinds of special cases. |
| 333 Result<Element> enclosingBlock(Node* node, EditingBoundaryCrossingRule rule) | 333 Result<Element> enclosingBlock(const Handle<Node>& node, EditingBoundaryCrossing
Rule rule) |
| 334 { | 334 { |
| 335 Handle<Node> enclosingNode = adoptRawResult(enclosingNodeOfType(firstPositio
nInOrBeforeNode(node), isBlock, rule)); | 335 Handle<Node> enclosingNode = enclosingNodeOfType(firstPositionInOrBeforeNode
(node), isBlock, rule); |
| 336 return enclosingNode && enclosingNode->isElementNode() ? toElement(enclosing
Node) : nullptr; | 336 return enclosingNode && enclosingNode->isElementNode() ? toElement(enclosing
Node) : nullptr; |
| 337 } | 337 } |
| 338 | 338 |
| 339 TextDirection directionOfEnclosingBlock(const Position& position) | 339 TextDirection directionOfEnclosingBlock(const Position& position) |
| 340 { | 340 { |
| 341 Handle<Node> enclosingBlockNode = enclosingBlock(position.containerNode().ha
ndle().raw()); | 341 Handle<Node> enclosingBlockNode = enclosingBlock(position.containerNode()); |
| 342 if (!enclosingBlockNode) | 342 if (!enclosingBlockNode) |
| 343 return LTR; | 343 return LTR; |
| 344 RenderObject* renderer = enclosingBlockNode->renderer(); | 344 RenderObject* renderer = enclosingBlockNode->renderer(); |
| 345 return renderer ? renderer->style()->direction() : LTR; | 345 return renderer ? renderer->style()->direction() : LTR; |
| 346 } | 346 } |
| 347 | 347 |
| 348 // This method is used to create positions in the DOM. It returns the maximum va
lid offset | 348 // This method is used to create positions in the DOM. It returns the maximum va
lid offset |
| 349 // in a node. It returns 1 for some elements even though they do not have childr
en, which | 349 // in a node. It returns 1 for some elements even though they do not have childr
en, which |
| 350 // creates technically invalid DOM Positions. Be sure to call parentAnchoredEqui
valent | 350 // creates technically invalid DOM Positions. Be sure to call parentAnchoredEqui
valent |
| 351 // on a Position before using it to create a DOM Range, or an exception will be
thrown. | 351 // on a Position before using it to create a DOM Range, or an exception will be
thrown. |
| 352 int lastOffsetForEditing(const Node* node) | 352 int lastOffsetForEditing(const Handle<const Node>& node) |
| 353 { | 353 { |
| 354 ASSERT(node); | 354 ASSERT(node); |
| 355 if (!node) | 355 if (!node) |
| 356 return 0; | 356 return 0; |
| 357 if (node->offsetInCharacters()) | 357 if (node->offsetInCharacters()) |
| 358 return node->maxCharacterOffset(); | 358 return node->maxCharacterOffset(); |
| 359 | 359 |
| 360 if (node->hasChildNodes()) | 360 if (node->hasChildNodes()) |
| 361 return node->childNodeCount(); | 361 return node->childNodeCount(); |
| 362 | 362 |
| (...skipping 22 matching lines...) Expand all Loading... |
| 385 } else { | 385 } else { |
| 386 rebalancedString[i] = ' '; | 386 rebalancedString[i] = ' '; |
| 387 previousCharacterWasSpace = true; | 387 previousCharacterWasSpace = true; |
| 388 } | 388 } |
| 389 | 389 |
| 390 } | 390 } |
| 391 | 391 |
| 392 return String::adopt(rebalancedString); | 392 return String::adopt(rebalancedString); |
| 393 } | 393 } |
| 394 | 394 |
| 395 bool isTableStructureNode(const Node *node) | 395 bool isTableStructureNode(const Handle<const Node>& node) |
| 396 { | 396 { |
| 397 RenderObject* renderer = node->renderer(); | 397 RenderObject* renderer = node->renderer(); |
| 398 return (renderer && (renderer->isTableCell() || renderer->isTableRow() || re
nderer->isTableSection() || renderer->isRenderTableCol())); | 398 return (renderer && (renderer->isTableCell() || renderer->isTableRow() || re
nderer->isTableSection() || renderer->isRenderTableCol())); |
| 399 } | 399 } |
| 400 | 400 |
| 401 const String& nonBreakingSpaceString() | 401 const String& nonBreakingSpaceString() |
| 402 { | 402 { |
| 403 DEFINE_STATIC_LOCAL(String, nonBreakingSpaceString, (&noBreakSpace, 1)); | 403 DEFINE_STATIC_LOCAL(String, nonBreakingSpaceString, (&noBreakSpace, 1)); |
| 404 return nonBreakingSpaceString; | 404 return nonBreakingSpaceString; |
| 405 } | 405 } |
| 406 | 406 |
| 407 // FIXME: need to dump this | 407 // FIXME: need to dump this |
| 408 bool isSpecialElement(const Node *n) | 408 bool isSpecialElement(const Handle<const Node>& n) |
| 409 { | 409 { |
| 410 if (!n) | 410 if (!n) |
| 411 return false; | 411 return false; |
| 412 | 412 |
| 413 if (!n->isHTMLElement()) | 413 if (!n->isHTMLElement()) |
| 414 return false; | 414 return false; |
| 415 | 415 |
| 416 if (n->isLink()) | 416 if (n->isLink()) |
| 417 return true; | 417 return true; |
| 418 | 418 |
| 419 RenderObject* renderer = n->renderer(); | 419 RenderObject* renderer = n->renderer(); |
| 420 if (!renderer) | 420 if (!renderer) |
| 421 return false; | 421 return false; |
| 422 | 422 |
| 423 if (renderer->style()->display() == TABLE || renderer->style()->display() ==
INLINE_TABLE) | 423 if (renderer->style()->display() == TABLE || renderer->style()->display() ==
INLINE_TABLE) |
| 424 return true; | 424 return true; |
| 425 | 425 |
| 426 if (renderer->style()->isFloating()) | 426 if (renderer->style()->isFloating()) |
| 427 return true; | 427 return true; |
| 428 | 428 |
| 429 if (renderer->style()->position() != StaticPosition) | 429 if (renderer->style()->position() != StaticPosition) |
| 430 return true; | 430 return true; |
| 431 | 431 |
| 432 return false; | 432 return false; |
| 433 } | 433 } |
| 434 | 434 |
| 435 static Node* firstInSpecialElement(const Position& pos) | 435 static Result<Node> firstInSpecialElement(const Position& pos) |
| 436 { | 436 { |
| 437 HandleScope scope; | 437 HandleScope scope; |
| 438 Handle<Node> rootEditableElement = pos.containerNode()->rootEditableElement(
); | 438 Handle<Node> rootEditableElement = pos.containerNode()->rootEditableElement(
); |
| 439 for (Handle<Node> n = pos.deprecatedNode(); n && n->rootEditableElement() ==
rootEditableElement; n = n->parentNode()) { | 439 for (Handle<Node> n = pos.deprecatedNode(); n && n->rootEditableElement() ==
rootEditableElement; n = n->parentNode()) { |
| 440 HandleScope scope; | 440 HandleScope scope; |
| 441 if (isSpecialElement(n.raw())) { | 441 if (isSpecialElement(n)) { |
| 442 VisiblePosition vPos = VisiblePosition(pos, DOWNSTREAM); | 442 VisiblePosition vPos = VisiblePosition(pos, DOWNSTREAM); |
| 443 VisiblePosition firstInElement = VisiblePosition(firstPositionInOrBe
foreNode(n.raw()), DOWNSTREAM); | 443 VisiblePosition firstInElement = VisiblePosition(firstPositionInOrBe
foreNode(n), DOWNSTREAM); |
| 444 if (isTableElement(n.raw()) && vPos == firstInElement.next()) | 444 if (isTableElement(n) && vPos == firstInElement.next()) |
| 445 return n.raw(); | 445 return n; |
| 446 if (vPos == firstInElement) | 446 if (vPos == firstInElement) |
| 447 return n.raw(); | 447 return n; |
| 448 } | 448 } |
| 449 } | 449 } |
| 450 return 0; | 450 return nullptr; |
| 451 } | 451 } |
| 452 | 452 |
| 453 static Node* lastInSpecialElement(const Position& pos) | 453 static Result<Node> lastInSpecialElement(const Position& pos) |
| 454 { | 454 { |
| 455 HandleScope scope; | 455 HandleScope scope; |
| 456 Handle<Node> rootEditableElement = pos.containerNode()->rootEditableElement(
); | 456 Handle<Node> rootEditableElement = pos.containerNode()->rootEditableElement(
); |
| 457 for (Handle<Node> n = pos.deprecatedNode(); n && n->rootEditableElement() ==
rootEditableElement; n = n->parentNode()) | 457 for (Handle<Node> n = pos.deprecatedNode(); n && n->rootEditableElement() ==
rootEditableElement; n = n->parentNode()) { |
| 458 if (isSpecialElement(n.raw())) { | 458 HandleScope scope; |
| 459 if (isSpecialElement(n)) { |
| 459 VisiblePosition vPos = VisiblePosition(pos, DOWNSTREAM); | 460 VisiblePosition vPos = VisiblePosition(pos, DOWNSTREAM); |
| 460 VisiblePosition lastInElement = VisiblePosition(lastPositionInOrAfte
rNode(n.raw()), DOWNSTREAM); | 461 VisiblePosition lastInElement = VisiblePosition(lastPositionInOrAfte
rNode(n), DOWNSTREAM); |
| 461 if (isTableElement(n.raw()) && vPos == lastInElement.previous()) | 462 if (isTableElement(n) && vPos == lastInElement.previous()) |
| 462 return n.raw(); | 463 return n; |
| 463 if (vPos == lastInElement) | 464 if (vPos == lastInElement) |
| 464 return n.raw(); | 465 return n; |
| 465 } | 466 } |
| 466 return 0; | 467 } |
| 468 return nullptr; |
| 467 } | 469 } |
| 468 | 470 |
| 469 bool isFirstVisiblePositionInSpecialElement(const Position& pos) | 471 bool isFirstVisiblePositionInSpecialElement(const Position& pos) |
| 470 { | 472 { |
| 471 return firstInSpecialElement(pos); | 473 return firstInSpecialElement(pos); |
| 472 } | 474 } |
| 473 | 475 |
| 474 Position positionBeforeContainingSpecialElement(const Position& pos, Node** cont
ainingSpecialElement) | 476 Position positionBeforeContainingSpecialElement(const Position& pos, Handle<Node
>* containingSpecialElement) |
| 475 { | 477 { |
| 476 Node* n = firstInSpecialElement(pos); | 478 Handle<Node> n = firstInSpecialElement(pos); |
| 477 if (!n) | 479 if (!n) |
| 478 return pos; | 480 return pos; |
| 479 Position result = positionInParentBeforeNode(adoptRawResult(n)); | 481 Position result = positionInParentBeforeNode(n); |
| 480 if (result.isNull() || result.deprecatedNode()->rootEditableElement() != pos
.deprecatedNode()->rootEditableElement()) | 482 if (result.isNull() || result.deprecatedNode()->rootEditableElement() != pos
.deprecatedNode()->rootEditableElement()) |
| 481 return pos; | 483 return pos; |
| 482 if (containingSpecialElement) | 484 if (containingSpecialElement) |
| 483 *containingSpecialElement = n; | 485 *containingSpecialElement = n; |
| 484 return result; | 486 return result; |
| 485 } | 487 } |
| 486 | 488 |
| 487 bool isLastVisiblePositionInSpecialElement(const Position& pos) | 489 bool isLastVisiblePositionInSpecialElement(const Position& pos) |
| 488 { | 490 { |
| 489 return lastInSpecialElement(pos); | 491 return lastInSpecialElement(pos); |
| 490 } | 492 } |
| 491 | 493 |
| 492 Position positionAfterContainingSpecialElement(const Position& pos, Node **conta
iningSpecialElement) | 494 Position positionAfterContainingSpecialElement(const Position& pos, Handle<Node>
* containingSpecialElement) |
| 493 { | 495 { |
| 494 Node* n = lastInSpecialElement(pos); | 496 Handle<Node> n = lastInSpecialElement(pos); |
| 495 if (!n) | 497 if (!n) |
| 496 return pos; | 498 return pos; |
| 497 Position result = positionInParentAfterNode(adoptRawResult(n)); | 499 Position result = positionInParentAfterNode(n); |
| 498 if (result.isNull() || result.deprecatedNode()->rootEditableElement() != pos
.deprecatedNode()->rootEditableElement()) | 500 if (result.isNull() || result.deprecatedNode()->rootEditableElement() != pos
.deprecatedNode()->rootEditableElement()) |
| 499 return pos; | 501 return pos; |
| 500 if (containingSpecialElement) | 502 if (containingSpecialElement) |
| 501 *containingSpecialElement = n; | 503 *containingSpecialElement = n; |
| 502 return result; | 504 return result; |
| 503 } | 505 } |
| 504 | 506 |
| 505 Position positionOutsideContainingSpecialElement(const Position &pos, Node **con
tainingSpecialElement) | 507 Position positionOutsideContainingSpecialElement(const Position &pos, Handle<Nod
e>* containingSpecialElement) |
| 506 { | 508 { |
| 507 if (isFirstVisiblePositionInSpecialElement(pos)) | 509 if (isFirstVisiblePositionInSpecialElement(pos)) |
| 508 return positionBeforeContainingSpecialElement(pos, containingSpecialElem
ent); | 510 return positionBeforeContainingSpecialElement(pos, containingSpecialElem
ent); |
| 509 if (isLastVisiblePositionInSpecialElement(pos)) | 511 if (isLastVisiblePositionInSpecialElement(pos)) |
| 510 return positionAfterContainingSpecialElement(pos, containingSpecialEleme
nt); | 512 return positionAfterContainingSpecialElement(pos, containingSpecialEleme
nt); |
| 511 return pos; | 513 return pos; |
| 512 } | 514 } |
| 513 | 515 |
| 514 Node* isFirstPositionAfterTable(const VisiblePosition& visiblePosition) | 516 Result<Node> isFirstPositionAfterTable(const VisiblePosition& visiblePosition) |
| 515 { | 517 { |
| 516 Position upstream(visiblePosition.deepEquivalent().upstream()); | 518 Position upstream(visiblePosition.deepEquivalent().upstream()); |
| 517 if (upstream.deprecatedNode() && upstream.deprecatedNode()->renderer() && up
stream.deprecatedNode()->renderer()->isTable() && upstream.atLastEditingPosition
ForNode()) | 519 if (upstream.deprecatedNode() && upstream.deprecatedNode()->renderer() && up
stream.deprecatedNode()->renderer()->isTable() && upstream.atLastEditingPosition
ForNode()) |
| 518 return upstream.deprecatedNode().handle().raw(); | 520 return upstream.deprecatedNode(); |
| 519 | 521 |
| 520 return 0; | 522 return nullptr; |
| 521 } | 523 } |
| 522 | 524 |
| 523 Node* isLastPositionBeforeTable(const VisiblePosition& visiblePosition) | 525 Result<Node> isLastPositionBeforeTable(const VisiblePosition& visiblePosition) |
| 524 { | 526 { |
| 525 Position downstream(visiblePosition.deepEquivalent().downstream()); | 527 Position downstream(visiblePosition.deepEquivalent().downstream()); |
| 526 if (downstream.deprecatedNode() && downstream.deprecatedNode()->renderer() &
& downstream.deprecatedNode()->renderer()->isTable() && downstream.atFirstEditin
gPositionForNode()) | 528 if (downstream.deprecatedNode() && downstream.deprecatedNode()->renderer() &
& downstream.deprecatedNode()->renderer()->isTable() && downstream.atFirstEditin
gPositionForNode()) |
| 527 return downstream.deprecatedNode().handle().raw(); | 529 return downstream.deprecatedNode(); |
| 528 | 530 |
| 529 return 0; | 531 return nullptr; |
| 530 } | 532 } |
| 531 | 533 |
| 532 // Returns the visible position at the beginning of a node | 534 // Returns the visible position at the beginning of a node |
| 533 VisiblePosition visiblePositionBeforeNode(Node* node) | 535 VisiblePosition visiblePositionBeforeNode(const Handle<Node>& node) |
| 534 { | 536 { |
| 535 ASSERT(node); | 537 ASSERT(node); |
| 536 if (node->childNodeCount()) | 538 if (node->childNodeCount()) |
| 537 return VisiblePosition(firstPositionInOrBeforeNode(node), DOWNSTREAM); | 539 return VisiblePosition(firstPositionInOrBeforeNode(node), DOWNSTREAM); |
| 538 ASSERT(node->parentNode()); | 540 ASSERT(node->parentNode()); |
| 539 ASSERT(!node->parentNode()->isShadowRoot()); | 541 ASSERT(!node->parentNode()->isShadowRoot()); |
| 540 return positionInParentBeforeNode(adoptRawResult(node)); | 542 return positionInParentBeforeNode(node); |
| 541 } | 543 } |
| 542 | 544 |
| 543 // Returns the visible position at the ending of a node | 545 // Returns the visible position at the ending of a node |
| 544 VisiblePosition visiblePositionAfterNode(Node* node) | 546 VisiblePosition visiblePositionAfterNode(const Handle<Node>& node) |
| 545 { | 547 { |
| 546 ASSERT(node); | 548 ASSERT(node); |
| 547 if (node->childNodeCount()) | 549 if (node->childNodeCount()) |
| 548 return VisiblePosition(lastPositionInOrAfterNode(node), DOWNSTREAM); | 550 return VisiblePosition(lastPositionInOrAfterNode(node), DOWNSTREAM); |
| 549 ASSERT(node->parentNode()); | 551 ASSERT(node->parentNode()); |
| 550 ASSERT(!node->parentNode()->isShadowRoot()); | 552 ASSERT(!node->parentNode()->isShadowRoot()); |
| 551 return positionInParentAfterNode(adoptRawResult(node)); | 553 return positionInParentAfterNode(node); |
| 552 } | 554 } |
| 553 | 555 |
| 554 // Create a range object with two visible positions, start and end. | 556 // Create a range object with two visible positions, start and end. |
| 555 // create(Handle<Document>, const Position&, const Position&); will use deprecat
edEditingOffset | 557 // create(Handle<Document>, const Position&, const Position&); will use deprecat
edEditingOffset |
| 556 // Use this function instead of create a regular range object (avoiding editing
offset). | 558 // Use this function instead of create a regular range object (avoiding editing
offset). |
| 557 Result<Range> createRange(const Handle<Document>& document, const VisiblePositio
n& start, const VisiblePosition& end, ExceptionCode& ec) | 559 Result<Range> createRange(const Handle<Document>& document, const VisiblePositio
n& start, const VisiblePosition& end, ExceptionCode& ec) |
| 558 { | 560 { |
| 559 ec = 0; | 561 ec = 0; |
| 560 Handle<Range> selectedRange = Range::create(document); | 562 Handle<Range> selectedRange = Range::create(document); |
| 561 selectedRange->setStart(start.deepEquivalent().containerNode(), start.deepEq
uivalent().computeOffsetInContainerNode(), ec); | 563 selectedRange->setStart(start.deepEquivalent().containerNode(), start.deepEq
uivalent().computeOffsetInContainerNode(), ec); |
| 562 if (!ec) | 564 if (!ec) |
| 563 selectedRange->setEnd(end.deepEquivalent().containerNode(), end.deepEqui
valent().computeOffsetInContainerNode(), ec); | 565 selectedRange->setEnd(end.deepEquivalent().containerNode(), end.deepEqui
valent().computeOffsetInContainerNode(), ec); |
| 564 return selectedRange; | 566 return selectedRange; |
| 565 } | 567 } |
| 566 | 568 |
| 567 // Extend rangeToExtend to include nodes that wraps range and visibly starts and
ends inside or at the boudnaries of maximumRange | 569 // Extend rangeToExtend to include nodes that wraps range and visibly starts and
ends inside or at the boudnaries of maximumRange |
| 568 // e.g. if the original range spaned "hello" in <div>hello</div>, then this func
tion extends the range to contain div's around it. | 570 // e.g. if the original range spaned "hello" in <div>hello</div>, then this func
tion extends the range to contain div's around it. |
| 569 // Call this function before copying / moving paragraphs to contain all wrapping
nodes. | 571 // Call this function before copying / moving paragraphs to contain all wrapping
nodes. |
| 570 // This function stops extending the range immediately below rootNode; i.e. the
extended range can contain a child node of rootNode | 572 // This function stops extending the range immediately below rootNode; i.e. the
extended range can contain a child node of rootNode |
| 571 // but it can never contain rootNode itself. | 573 // but it can never contain rootNode itself. |
| 572 Result<Range> extendRangeToWrappingNodes(const Handle<Range>& range, const Handl
e<const Range>& maximumRange, const Node* rootNode) | 574 Result<Range> extendRangeToWrappingNodes(const Handle<Range>& range, const Handl
e<const Range>& maximumRange, const Handle<const Node>& rootNode) |
| 573 { | 575 { |
| 574 ASSERT(range); | 576 ASSERT(range); |
| 575 ASSERT(maximumRange); | 577 ASSERT(maximumRange); |
| 576 | 578 |
| 577 Handle<Node> ancestor = range->commonAncestorContainer(IGNORE_EXCEPTION); //
Find the closest common ancestor. | 579 Handle<Node> ancestor = range->commonAncestorContainer(IGNORE_EXCEPTION); //
Find the closest common ancestor. |
| 578 Node* highestNode = 0; | 580 Handle<Node> highestNode; |
| 579 // traverse through ancestors as long as they are contained within the range
, content-editable, and below rootNode (could be =0). | 581 // traverse through ancestors as long as they are contained within the range
, content-editable, and below rootNode (could be =0). |
| 580 while (ancestor && ancestor->rendererIsEditable() && isNodeVisiblyContainedW
ithin(ancestor.raw(), maximumRange) && ancestor != rootNode) { | 582 while (ancestor && ancestor->rendererIsEditable() && isNodeVisiblyContainedW
ithin(ancestor, maximumRange) && ancestor != rootNode) { |
| 581 HandleScope scope; | 583 HandleScope scope; |
| 582 highestNode = ancestor.raw(); | 584 highestNode = ancestor; |
| 583 ancestor = ancestor->parentNode(); | 585 ancestor = ancestor->parentNode(); |
| 584 } | 586 } |
| 585 | 587 |
| 586 if (!highestNode) | 588 if (!highestNode) |
| 587 return range; | 589 return range; |
| 588 | 590 |
| 589 // Create new range with the highest editable node contained within the rang
e | 591 // Create new range with the highest editable node contained within the rang
e |
| 590 Handle<Range> extendedRange = Range::create(range->ownerDocument()); | 592 Handle<Range> extendedRange = Range::create(range->ownerDocument()); |
| 591 extendedRange->selectNode(adoptRawResult(highestNode), IGNORE_EXCEPTION); | 593 extendedRange->selectNode(highestNode, IGNORE_EXCEPTION); |
| 592 return extendedRange; | 594 return extendedRange; |
| 593 } | 595 } |
| 594 | 596 |
| 595 bool isListElement(Node *n) | 597 bool isListElement(const Handle<Node>& n) |
| 596 { | 598 { |
| 597 return (n && (n->hasTagName(ulTag) || n->hasTagName(olTag) || n->hasTagName(
dlTag))); | 599 return (n && (n->hasTagName(ulTag) || n->hasTagName(olTag) || n->hasTagName(
dlTag))); |
| 598 } | 600 } |
| 599 | 601 |
| 600 bool isListItem(const Node *n) | 602 bool isListItem(const Handle<const Node>& n) |
| 601 { | 603 { |
| 602 return n && n->renderer() && n->renderer()->isListItem(); | 604 return n && n->renderer() && n->renderer()->isListItem(); |
| 603 } | 605 } |
| 604 | 606 |
| 605 Node* enclosingNodeWithTag(const Position& p, const QualifiedName& tagName) | 607 Result<Node> enclosingNodeWithTag(const Position& p, const QualifiedName& tagNam
e) |
| 606 { | 608 { |
| 607 HandleScope scope; | 609 HandleScope scope; |
| 608 | 610 |
| 609 if (p.isNull()) | 611 if (p.isNull()) |
| 610 return 0; | 612 return nullptr; |
| 611 | 613 |
| 612 Node* root = highestEditableRoot(p); | 614 Handle<Node> root = highestEditableRoot(p); |
| 613 for (Handle<Node> n = p.deprecatedNode(); n; n = n->parentNode()) { | 615 for (Handle<Node> n = p.deprecatedNode(); n; n = n->parentNode()) { |
| 614 HandleScope scope; | 616 HandleScope scope; |
| 615 if (root && !n->rendererIsEditable()) | 617 if (root && !n->rendererIsEditable()) |
| 616 continue; | 618 continue; |
| 617 if (n->hasTagName(tagName)) | 619 if (n->hasTagName(tagName)) |
| 618 return n.raw(); | 620 return n; |
| 619 if (n == root) | 621 if (n == root) |
| 620 return 0; | 622 return nullptr; |
| 621 } | 623 } |
| 622 | 624 |
| 623 return 0; | 625 return nullptr; |
| 624 } | 626 } |
| 625 | 627 |
| 626 Node* enclosingNodeOfType(const Position& p, bool (*nodeIsOfType)(const Node*),
EditingBoundaryCrossingRule rule) | 628 Result<Node> enclosingNodeOfType(const Position& p, bool (*nodeIsOfType)(const H
andle<const Node>&), EditingBoundaryCrossingRule rule) |
| 627 { | 629 { |
| 628 HandleScope scope; | 630 HandleScope scope; |
| 629 | 631 |
| 630 // FIXME: support CanSkipCrossEditingBoundary | 632 // FIXME: support CanSkipCrossEditingBoundary |
| 631 ASSERT(rule == CanCrossEditingBoundary || rule == CannotCrossEditingBoundary
); | 633 ASSERT(rule == CanCrossEditingBoundary || rule == CannotCrossEditingBoundary
); |
| 632 if (p.isNull()) | 634 if (p.isNull()) |
| 633 return 0; | 635 return nullptr; |
| 634 | 636 |
| 635 Node* root = rule == CannotCrossEditingBoundary ? highestEditableRoot(p) : 0
; | 637 Handle<Node> root = rule == CannotCrossEditingBoundary ? highestEditableRoot
(p) : nullptr; |
| 636 for (Handle<Node> n = p.deprecatedNode(); n; n = n->parentNode()) { | 638 for (Handle<Node> n = p.deprecatedNode(); n; n = n->parentNode()) { |
| 637 HandleScope scope; | 639 HandleScope scope; |
| 638 // Don't return a non-editable node if the input position was editable,
since | 640 // Don't return a non-editable node if the input position was editable,
since |
| 639 // the callers from editing will no doubt want to perform editing inside
the returned node. | 641 // the callers from editing will no doubt want to perform editing inside
the returned node. |
| 640 if (root && !n->rendererIsEditable()) | 642 if (root && !n->rendererIsEditable()) |
| 641 continue; | 643 continue; |
| 642 if (nodeIsOfType(n.raw())) | 644 if (nodeIsOfType(n)) |
| 643 return n.raw(); | 645 return n; |
| 644 if (n.raw() == root) | 646 if (n == root) |
| 645 return 0; | 647 return nullptr; |
| 646 } | 648 } |
| 647 | 649 |
| 648 return 0; | 650 return nullptr; |
| 649 } | 651 } |
| 650 | 652 |
| 651 Node* highestEnclosingNodeOfType(const Position& p, bool (*nodeIsOfType)(const N
ode*), EditingBoundaryCrossingRule rule, Node* stayWithin) | 653 Result<Node> highestEnclosingNodeOfType(const Position& p, bool (*nodeIsOfType)(
const Handle<const Node>&), EditingBoundaryCrossingRule rule, const Handle<Node>
& stayWithin) |
| 652 { | 654 { |
| 653 HandleScope scope; | 655 HandleScope scope; |
| 654 | 656 |
| 655 Node* highest = 0; | 657 Handle<Node> highest; |
| 656 Node* root = rule == CannotCrossEditingBoundary ? highestEditableRoot(p) : 0
; | 658 Handle<Node> root = rule == CannotCrossEditingBoundary ? highestEditableRoot
(p) : nullptr; |
| 657 for (Handle<Node> n = p.containerNode(); n && n.raw() != stayWithin; n = n->
parentNode()) { | 659 for (Handle<Node> n = p.containerNode(); n && n != stayWithin; n = n->parent
Node()) { |
| 658 HandleScope scope; | 660 HandleScope scope; |
| 659 if (root && !n->rendererIsEditable()) | 661 if (root && !n->rendererIsEditable()) |
| 660 continue; | 662 continue; |
| 661 if (nodeIsOfType(n.raw())) | 663 if (nodeIsOfType(n)) |
| 662 highest = n.raw(); | 664 highest = n; |
| 663 if (n == root) | 665 if (n == root) |
| 664 break; | 666 break; |
| 665 } | 667 } |
| 666 | 668 |
| 667 return highest; | 669 return highest; |
| 668 } | 670 } |
| 669 | 671 |
| 670 static bool hasARenderedDescendant(Node* node, Node* excludedNode) | 672 static bool hasARenderedDescendant(const Handle<Node>& node, const Handle<Node>&
excludedNode) |
| 671 { | 673 { |
| 672 for (Handle<Node> n = node->firstChild(); n;) { | 674 for (Handle<Node> n = node->firstChild(); n;) { |
| 673 HandleScope scope; | 675 HandleScope scope; |
| 674 if (n == excludedNode) { | 676 if (n == excludedNode) { |
| 675 n = NodeTraversal::nextSkippingChildren(n, adoptRawResult(node)); | 677 n = NodeTraversal::nextSkippingChildren(n, node); |
| 676 continue; | 678 continue; |
| 677 } | 679 } |
| 678 if (n->renderer()) | 680 if (n->renderer()) |
| 679 return true; | 681 return true; |
| 680 n = NodeTraversal::next(n, adoptRawResult(node)); | 682 n = NodeTraversal::next(n, node); |
| 681 } | 683 } |
| 682 return false; | 684 return false; |
| 683 } | 685 } |
| 684 | 686 |
| 685 Node* highestNodeToRemoveInPruning(Node* node) | 687 Result<Node> highestNodeToRemoveInPruning(const Handle<Node>& node) |
| 686 { | 688 { |
| 687 HandleScope scope; | 689 HandleScope scope; |
| 688 Handle<Node> previousNode; | 690 Handle<Node> previousNode; |
| 689 Handle<Node> rootEditableElement = node ? node->rootEditableElement() : null
ptr; | 691 Handle<Node> rootEditableElement = node ? node->rootEditableElement() : null
ptr; |
| 690 Handle<Node> current = adoptRawResult(node); | 692 Handle<Node> current = node; |
| 691 for (; current; current = current->parentNode()) { | 693 for (; current; current = current->parentNode()) { |
| 692 HandleScope scope; | 694 HandleScope scope; |
| 693 if (RenderObject* renderer = current->renderer()) { | 695 if (RenderObject* renderer = current->renderer()) { |
| 694 if (!renderer->canHaveChildren() || hasARenderedDescendant(current.r
aw(), previousNode.raw()) || rootEditableElement == current) | 696 if (!renderer->canHaveChildren() || hasARenderedDescendant(current,
previousNode) || rootEditableElement == current) |
| 695 return previousNode.raw(); | 697 return previousNode; |
| 696 } | 698 } |
| 697 previousNode = current; | 699 previousNode = current; |
| 698 } | 700 } |
| 699 return 0; | 701 return nullptr; |
| 700 } | 702 } |
| 701 | 703 |
| 702 Node* enclosingTableCell(const Position& p) | 704 Result<Node> enclosingTableCell(const Position& p) |
| 703 { | 705 { |
| 704 return toElement(enclosingNodeOfType(p, isTableCell)); | 706 return toElement(enclosingNodeOfType(p, isTableCell)); |
| 705 } | 707 } |
| 706 | 708 |
| 707 Node* enclosingAnchorElement(const Position& p) | 709 Result<Node> enclosingAnchorElement(const Position& p) |
| 708 { | 710 { |
| 709 if (p.isNull()) | 711 if (p.isNull()) |
| 710 return 0; | 712 return nullptr; |
| 711 | 713 |
| 712 Handle<Node> node = p.deprecatedNode(); | 714 Handle<Node> node = p.deprecatedNode(); |
| 713 while (node && !(node->isElementNode() && node->isLink())) { | 715 while (node && !(node->isElementNode() && node->isLink())) { |
| 714 NoHandleScope scope; | 716 NoHandleScope scope; |
| 715 node = node->parentNode(); | 717 node = node->parentNode(); |
| 716 } | 718 } |
| 717 return node.raw(); | 719 return node; |
| 718 } | 720 } |
| 719 | 721 |
| 720 Result<HTMLElement> enclosingList(Node* node) | 722 Result<HTMLElement> enclosingList(const Handle<Node>& node) |
| 721 { | 723 { |
| 722 HandleScope scope; | 724 HandleScope scope; |
| 723 if (!node) | 725 if (!node) |
| 724 return nullptr; | 726 return nullptr; |
| 725 | 727 |
| 726 Node* root = highestEditableRoot(firstPositionInOrBeforeNode(node)); | 728 Handle<Node> root = highestEditableRoot(firstPositionInOrBeforeNode(node)); |
| 727 | 729 |
| 728 for (Handle<ContainerNode> n = node->parentNode(); n; n = n->parentNode()) { | 730 for (Handle<ContainerNode> n = node->parentNode(); n; n = n->parentNode()) { |
| 729 HandleScope scope; | 731 HandleScope scope; |
| 730 if (n->hasTagName(ulTag) || n->hasTagName(olTag)) | 732 if (n->hasTagName(ulTag) || n->hasTagName(olTag)) |
| 731 return toHTMLElement(n); | 733 return toHTMLElement(n); |
| 732 if (n == root) | 734 if (n == root) |
| 733 return nullptr; | 735 return nullptr; |
| 734 } | 736 } |
| 735 | 737 |
| 736 return nullptr; | 738 return nullptr; |
| 737 } | 739 } |
| 738 | 740 |
| 739 Node* enclosingListChild(Node *node) | 741 Result<Node> enclosingListChild(const Handle<Node>& node) |
| 740 { | 742 { |
| 741 if (!node) | 743 if (!node) |
| 742 return 0; | 744 return nullptr; |
| 743 | 745 |
| 744 HandleScope scope; | 746 HandleScope scope; |
| 745 | 747 |
| 746 // Check for a list item element, or for a node whose parent is a list eleme
nt. Such a node | 748 // Check for a list item element, or for a node whose parent is a list eleme
nt. Such a node |
| 747 // will appear visually as a list item (but without a list marker) | 749 // will appear visually as a list item (but without a list marker) |
| 748 Node* root = highestEditableRoot(firstPositionInOrBeforeNode(node)); | 750 Handle<Node> root = highestEditableRoot(firstPositionInOrBeforeNode(node)); |
| 749 | 751 |
| 750 // FIXME: This function is inappropriately named if it starts with node inst
ead of node->parentNode() | 752 // FIXME: This function is inappropriately named if it starts with node inst
ead of node->parentNode() |
| 751 for (Node* n = node; n && n->parentNode(); n = n->parentNode().handle().raw(
)) { | 753 for (Handle<Node> n = node; n && n->parentNode(); n = n->parentNode()) { |
| 752 HandleScope scope; | 754 HandleScope scope; |
| 753 if (n->hasTagName(liTag) || (isListElement(n->parentNode().handle().raw(
)) && n != root)) | 755 if (n->hasTagName(liTag) || (isListElement(n->parentNode()) && n != root
)) |
| 754 return n; | 756 return n; |
| 755 if (n == root || isTableCell(n)) | 757 if (n == root || isTableCell(n)) |
| 756 return 0; | 758 return nullptr; |
| 757 } | 759 } |
| 758 | 760 |
| 759 return 0; | 761 return nullptr; |
| 760 } | 762 } |
| 761 | 763 |
| 762 static Result<HTMLElement> embeddedSublist(Node* listItem) | 764 static Result<HTMLElement> embeddedSublist(const Handle<Node>& listItem) |
| 763 { | 765 { |
| 764 // Check the DOM so that we'll find collapsed sublists without renderers. | 766 // Check the DOM so that we'll find collapsed sublists without renderers. |
| 765 for (Handle<Node> n = listItem->firstChild(); n; n = n->nextSibling()) { | 767 for (Handle<Node> n = listItem->firstChild(); n; n = n->nextSibling()) { |
| 766 if (isListElement(n.raw())) | 768 HandleScope scope; |
| 769 if (isListElement(n)) |
| 767 return toHTMLElement(n); | 770 return toHTMLElement(n); |
| 768 } | 771 } |
| 769 | 772 |
| 770 return nullptr; | 773 return nullptr; |
| 771 } | 774 } |
| 772 | 775 |
| 773 static Node* appendedSublist(Node* listItem) | 776 static Result<Node> appendedSublist(const Handle<Node>& listItem) |
| 774 { | 777 { |
| 775 // Check the DOM so that we'll find collapsed sublists without renderers. | 778 // Check the DOM so that we'll find collapsed sublists without renderers. |
| 776 for (Handle<Node> n = listItem->nextSibling(); n; n = n->nextSibling()) { | 779 for (Handle<Node> n = listItem->nextSibling(); n; n = n->nextSibling()) { |
| 777 if (isListElement(n.raw())) | 780 HandleScope scope; |
| 778 return toHTMLElement(n).handle().raw(); | 781 if (isListElement(n)) |
| 782 return toHTMLElement(n); |
| 779 if (isListItem(listItem)) | 783 if (isListItem(listItem)) |
| 780 return 0; | 784 return nullptr; |
| 781 } | 785 } |
| 782 | 786 |
| 783 return 0; | 787 return nullptr; |
| 784 } | 788 } |
| 785 | 789 |
| 786 // FIXME: This method should not need to call isStartOfParagraph/isEndOfParagrap
h | 790 // FIXME: This method should not need to call isStartOfParagraph/isEndOfParagrap
h |
| 787 Node* enclosingEmptyListItem(const VisiblePosition& visiblePos) | 791 Result<Node> enclosingEmptyListItem(const VisiblePosition& visiblePos) |
| 788 { | 792 { |
| 789 // Check that position is on a line by itself inside a list item | 793 // Check that position is on a line by itself inside a list item |
| 790 Node* listChildNode = enclosingListChild(visiblePos.deepEquivalent().depreca
tedNode().handle().raw()); | 794 Handle<Node> listChildNode = enclosingListChild(visiblePos.deepEquivalent().
deprecatedNode()); |
| 791 if (!listChildNode || !isStartOfParagraph(visiblePos) || !isEndOfParagraph(v
isiblePos)) | 795 if (!listChildNode || !isStartOfParagraph(visiblePos) || !isEndOfParagraph(v
isiblePos)) |
| 792 return 0; | 796 return nullptr; |
| 793 | 797 |
| 794 VisiblePosition firstInListChild(firstPositionInOrBeforeNode(listChildNode))
; | 798 VisiblePosition firstInListChild(firstPositionInOrBeforeNode(listChildNode))
; |
| 795 VisiblePosition lastInListChild(lastPositionInOrAfterNode(listChildNode)); | 799 VisiblePosition lastInListChild(lastPositionInOrAfterNode(listChildNode)); |
| 796 | 800 |
| 797 if (firstInListChild != visiblePos || lastInListChild != visiblePos) | 801 if (firstInListChild != visiblePos || lastInListChild != visiblePos) |
| 798 return 0; | 802 return nullptr; |
| 799 | 803 |
| 800 if (embeddedSublist(listChildNode) || appendedSublist(listChildNode)) | 804 if (embeddedSublist(listChildNode) || appendedSublist(listChildNode)) |
| 801 return 0; | 805 return nullptr; |
| 802 | 806 |
| 803 return listChildNode; | 807 return listChildNode; |
| 804 } | 808 } |
| 805 | 809 |
| 806 Result<HTMLElement> outermostEnclosingList(Node* node, Node* rootList) | 810 Result<HTMLElement> outermostEnclosingList(const Handle<Node>& node, const Handl
e<Node>& rootList) |
| 807 { | 811 { |
| 808 Handle<HTMLElement> list = enclosingList(node); | 812 Handle<HTMLElement> list = enclosingList(node); |
| 809 if (!list) | 813 if (!list) |
| 810 return nullptr; | 814 return nullptr; |
| 811 | 815 |
| 812 Handle<HTMLElement> nextList = enclosingList(list.raw()); | 816 Handle<HTMLElement> nextList = enclosingList(list); |
| 813 while (nextList) { | 817 while (nextList) { |
| 814 HandleScope scope; | 818 HandleScope scope; |
| 815 if (nextList == rootList) | 819 if (nextList == rootList) |
| 816 break; | 820 break; |
| 817 list = nextList; | 821 list = nextList; |
| 818 nextList = enclosingList(list.raw()); | 822 nextList = enclosingList(list); |
| 819 } | 823 } |
| 820 | 824 |
| 821 return list; | 825 return list; |
| 822 } | 826 } |
| 823 | 827 |
| 824 bool canMergeLists(const Handle<Element>& firstList, const Handle<Element>& seco
ndList) | 828 bool canMergeLists(const Handle<Element>& firstList, const Handle<Element>& seco
ndList) |
| 825 { | 829 { |
| 826 if (!firstList || !secondList || !firstList->isHTMLElement() || !secondList-
>isHTMLElement()) | 830 if (!firstList || !secondList || !firstList->isHTMLElement() || !secondList-
>isHTMLElement()) |
| 827 return false; | 831 return false; |
| 828 | 832 |
| 829 return firstList->hasTagName(secondList->tagQName()) // make sure the list t
ypes match (ol vs. ul) | 833 return firstList->hasTagName(secondList->tagQName()) // make sure the list t
ypes match (ol vs. ul) |
| 830 && firstList->rendererIsEditable() && secondList->rendererIsEditable() /
/ both lists are editable | 834 && firstList->rendererIsEditable() && secondList->rendererIsEditable() /
/ both lists are editable |
| 831 && firstList->rootEditableElement() == secondList->rootEditableElement()
// don't cross editing boundaries | 835 && firstList->rootEditableElement() == secondList->rootEditableElement()
// don't cross editing boundaries |
| 832 && isVisiblyAdjacent(positionInParentAfterNode(firstList), positionInPar
entBeforeNode(secondList)); | 836 && isVisiblyAdjacent(positionInParentAfterNode(firstList), positionInPar
entBeforeNode(secondList)); |
| 833 // Make sure there is no visible content between this li and the previous li
st | 837 // Make sure there is no visible content between this li and the previous li
st |
| 834 } | 838 } |
| 835 | 839 |
| 836 Result<Node> highestAncestor(const Handle<Node>& node) | 840 Result<Node> highestAncestor(const Handle<Node>& node) |
| 837 { | 841 { |
| 838 HandleScope scope; | 842 HandleScope scope; |
| 839 ASSERT(node); | 843 ASSERT(node); |
| 840 return node->rootNode(); | 844 return node->rootNode(); |
| 841 } | 845 } |
| 842 | 846 |
| 843 // FIXME: do not require renderer, so that this can be used within fragments, or
rename to isRenderedTable() | 847 // FIXME: do not require renderer, so that this can be used within fragments, or
rename to isRenderedTable() |
| 844 bool isTableElement(Node* n) | 848 bool isTableElement(const Handle<Node>& n) |
| 845 { | 849 { |
| 846 if (!n || !n->isElementNode()) | 850 if (!n || !n->isElementNode()) |
| 847 return false; | 851 return false; |
| 848 | 852 |
| 849 RenderObject* renderer = n->renderer(); | 853 RenderObject* renderer = n->renderer(); |
| 850 return (renderer && (renderer->style()->display() == TABLE || renderer->styl
e()->display() == INLINE_TABLE)); | 854 return (renderer && (renderer->style()->display() == TABLE || renderer->styl
e()->display() == INLINE_TABLE)); |
| 851 } | 855 } |
| 852 | 856 |
| 853 bool isTableCell(const Node* node) | 857 bool isTableCell(const Handle<const Node>& node) |
| 854 { | 858 { |
| 855 RenderObject* r = node->renderer(); | 859 RenderObject* r = node->renderer(); |
| 856 if (!r) | 860 if (!r) |
| 857 return node->hasTagName(tdTag) || node->hasTagName(thTag); | 861 return node->hasTagName(tdTag) || node->hasTagName(thTag); |
| 858 | 862 |
| 859 return r->isTableCell(); | 863 return r->isTableCell(); |
| 860 } | 864 } |
| 861 | 865 |
| 862 bool isEmptyTableCell(const Node* node) | 866 bool isEmptyTableCell(const Handle<const Node>& node) |
| 863 { | 867 { |
| 864 // Returns true IFF the passed in node is one of: | 868 // Returns true IFF the passed in node is one of: |
| 865 // .) a table cell with no children, | 869 // .) a table cell with no children, |
| 866 // .) a table cell with a single BR child, and which has no other child re
nderers, including :before and :after renderers | 870 // .) a table cell with a single BR child, and which has no other child re
nderers, including :before and :after renderers |
| 867 // .) the BR child of such a table cell | 871 // .) the BR child of such a table cell |
| 868 | 872 |
| 869 // Find rendered node | 873 // Find rendered node |
| 870 while (node && !node->renderer()) { | 874 Handle<const Node> current = node; |
| 875 while (current && !current->renderer()) { |
| 871 HandleScope scope; | 876 HandleScope scope; |
| 872 node = node->parentNode().handle().raw(); | 877 current = current->parentNode(); |
| 873 } | 878 } |
| 874 if (!node) | 879 if (!current) |
| 875 return false; | 880 return false; |
| 876 | 881 |
| 877 // Make sure the rendered node is a table cell or <br>. | 882 // Make sure the rendered node is a table cell or <br>. |
| 878 // If it's a <br>, then the parent node has to be a table cell. | 883 // If it's a <br>, then the parent node has to be a table cell. |
| 879 RenderObject* renderer = node->renderer(); | 884 RenderObject* renderer = current->renderer(); |
| 880 if (renderer->isBR()) { | 885 if (renderer->isBR()) { |
| 881 renderer = renderer->parent(); | 886 renderer = renderer->parent(); |
| 882 if (!renderer) | 887 if (!renderer) |
| 883 return false; | 888 return false; |
| 884 } | 889 } |
| 885 if (!renderer->isTableCell()) | 890 if (!renderer->isTableCell()) |
| 886 return false; | 891 return false; |
| 887 | 892 |
| 888 // Check that the table cell contains no child renderers except for perhaps
a single <br>. | 893 // Check that the table cell contains no child renderers except for perhaps
a single <br>. |
| 889 RenderObject* childRenderer = renderer->firstChild(); | 894 RenderObject* childRenderer = renderer->firstChild(); |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 930 Result<HTMLElement> createHTMLElement(const Handle<Document>& document, const Qu
alifiedName& name) | 935 Result<HTMLElement> createHTMLElement(const Handle<Document>& document, const Qu
alifiedName& name) |
| 931 { | 936 { |
| 932 return HTMLElementFactory::createHTMLElement(name, document, nullptr, false)
; | 937 return HTMLElementFactory::createHTMLElement(name, document, nullptr, false)
; |
| 933 } | 938 } |
| 934 | 939 |
| 935 Result<HTMLElement> createHTMLElement(const Handle<Document>& document, const At
omicString& tagName) | 940 Result<HTMLElement> createHTMLElement(const Handle<Document>& document, const At
omicString& tagName) |
| 936 { | 941 { |
| 937 return createHTMLElement(document, QualifiedName(nullAtom, tagName, xhtmlNam
espaceURI)); | 942 return createHTMLElement(document, QualifiedName(nullAtom, tagName, xhtmlNam
espaceURI)); |
| 938 } | 943 } |
| 939 | 944 |
| 940 bool isTabSpanNode(const Node *node) | 945 bool isTabSpanNode(const Handle<const Node>& node) |
| 941 { | 946 { |
| 942 return node && node->hasTagName(spanTag) && node->isElementNode() && static_
cast<const Element *>(node)->getAttribute(classAttr) == AppleTabSpanClass; | 947 return node && node->hasTagName(spanTag) && node->isElementNode() && Handle<
const Element>::cast(node)->getAttribute(classAttr) == AppleTabSpanClass; |
| 943 } | 948 } |
| 944 | 949 |
| 945 bool isTabSpanTextNode(const Node *node) | 950 bool isTabSpanTextNode(const Handle<const Node>& node) |
| 946 { | 951 { |
| 947 return node && node->isTextNode() && node->parentNode() && isTabSpanNode(nod
e->parentNode().handle().raw()); | 952 return node && node->isTextNode() && node->parentNode() && isTabSpanNode(nod
e->parentNode()); |
| 948 } | 953 } |
| 949 | 954 |
| 950 Node* tabSpanNode(const Node *node) | 955 Result<Node> tabSpanNode(const Handle<const Node>& node) |
| 951 { | 956 { |
| 952 return isTabSpanTextNode(node) ? node->parentNode().handle().raw() : 0; | 957 return isTabSpanTextNode(node) ? node->parentNode() : nullptr; |
| 953 } | 958 } |
| 954 | 959 |
| 955 Position positionOutsideTabSpan(const Position& pos) | 960 Position positionOutsideTabSpan(const Position& pos) |
| 956 { | 961 { |
| 957 Handle<Node> node = pos.containerNode(); | 962 Handle<Node> node = pos.containerNode(); |
| 958 if (isTabSpanTextNode(node.raw())) | 963 if (isTabSpanTextNode(node)) |
| 959 node = adoptRawResult(tabSpanNode(node.raw())); | 964 node = tabSpanNode(node); |
| 960 else if (!isTabSpanNode(node.raw())) | 965 else if (!isTabSpanNode(node)) |
| 961 return pos; | 966 return pos; |
| 962 | 967 |
| 963 if (node && VisiblePosition(pos) == lastPositionInNode(node)) | 968 if (node && VisiblePosition(pos) == lastPositionInNode(node)) |
| 964 return positionInParentAfterNode(node); | 969 return positionInParentAfterNode(node); |
| 965 | 970 |
| 966 return positionInParentBeforeNode(node); | 971 return positionInParentBeforeNode(node); |
| 967 } | 972 } |
| 968 | 973 |
| 969 Result<Element> createTabSpanElement(const Handle<Document>& document, PassRefPt
r<Node> prpTabTextNode) | 974 Result<Element> createTabSpanElement(const Handle<Document>& document, PassRefPt
r<Node> prpTabTextNode) |
| 970 { | 975 { |
| (...skipping 16 matching lines...) Expand all Loading... |
| 987 Result<Element> createTabSpanElement(const Handle<Document>& document, const Str
ing& tabText) | 992 Result<Element> createTabSpanElement(const Handle<Document>& document, const Str
ing& tabText) |
| 988 { | 993 { |
| 989 return createTabSpanElement(document, document->createTextNode(tabText).pass
RefPtr()); | 994 return createTabSpanElement(document, document->createTextNode(tabText).pass
RefPtr()); |
| 990 } | 995 } |
| 991 | 996 |
| 992 Result<Element> createTabSpanElement(const Handle<Document>& document) | 997 Result<Element> createTabSpanElement(const Handle<Document>& document) |
| 993 { | 998 { |
| 994 return createTabSpanElement(document, PassRefPtr<Node>()); | 999 return createTabSpanElement(document, PassRefPtr<Node>()); |
| 995 } | 1000 } |
| 996 | 1001 |
| 997 bool isNodeRendered(const Node *node) | 1002 bool isNodeRendered(const Handle<const Node>& node) |
| 998 { | 1003 { |
| 999 if (!node) | 1004 if (!node) |
| 1000 return false; | 1005 return false; |
| 1001 | 1006 |
| 1002 RenderObject* renderer = node->renderer(); | 1007 RenderObject* renderer = node->renderer(); |
| 1003 if (!renderer) | 1008 if (!renderer) |
| 1004 return false; | 1009 return false; |
| 1005 | 1010 |
| 1006 return renderer->style()->visibility() == VISIBLE; | 1011 return renderer->style()->visibility() == VISIBLE; |
| 1007 } | 1012 } |
| 1008 | 1013 |
| 1009 unsigned numEnclosingMailBlockquotes(const Position& p) | 1014 unsigned numEnclosingMailBlockquotes(const Position& p) |
| 1010 { | 1015 { |
| 1011 HandleScope scope; | 1016 HandleScope scope; |
| 1012 unsigned num = 0; | 1017 unsigned num = 0; |
| 1013 for (Handle<Node> n = p.deprecatedNode(); n; n = n->parentNode()) { | 1018 for (Handle<Node> n = p.deprecatedNode(); n; n = n->parentNode()) { |
| 1014 HandleScope scope; | 1019 HandleScope scope; |
| 1015 if (isMailBlockquote(n.raw())) | 1020 if (isMailBlockquote(n)) |
| 1016 num++; | 1021 num++; |
| 1017 } | 1022 } |
| 1018 | 1023 |
| 1019 return num; | 1024 return num; |
| 1020 } | 1025 } |
| 1021 | 1026 |
| 1022 void updatePositionForNodeRemoval(Position& position, Node* node) | 1027 void updatePositionForNodeRemoval(Position& position, const Handle<Node>& node) |
| 1023 { | 1028 { |
| 1024 if (position.isNull()) | 1029 if (position.isNull()) |
| 1025 return; | 1030 return; |
| 1026 switch (position.anchorType()) { | 1031 switch (position.anchorType()) { |
| 1027 case Position::PositionIsBeforeChildren: | 1032 case Position::PositionIsBeforeChildren: |
| 1028 if (position.containerNode() == node) | 1033 if (position.containerNode() == node) |
| 1029 position = positionInParentBeforeNode(adoptRawResult(node)); | 1034 position = positionInParentBeforeNode(node); |
| 1030 break; | 1035 break; |
| 1031 case Position::PositionIsAfterChildren: | 1036 case Position::PositionIsAfterChildren: |
| 1032 if (position.containerNode() == node) | 1037 if (position.containerNode() == node) |
| 1033 position = positionInParentAfterNode(adoptRawResult(node)); | 1038 position = positionInParentAfterNode(node); |
| 1034 break; | 1039 break; |
| 1035 case Position::PositionIsOffsetInAnchor: | 1040 case Position::PositionIsOffsetInAnchor: |
| 1036 if (position.containerNode() == node->parentNode() && static_cast<unsign
ed>(position.offsetInContainerNode()) > node->nodeIndex()) | 1041 if (position.containerNode() == node->parentNode() && static_cast<unsign
ed>(position.offsetInContainerNode()) > node->nodeIndex()) |
| 1037 position.moveToOffset(position.offsetInContainerNode() - 1); | 1042 position.moveToOffset(position.offsetInContainerNode() - 1); |
| 1038 else if (node->containsIncludingShadowDOM(position.containerNode())) | 1043 else if (node->containsIncludingShadowDOM(position.containerNode())) |
| 1039 position = positionInParentBeforeNode(adoptRawResult(node)); | 1044 position = positionInParentBeforeNode(node); |
| 1040 break; | 1045 break; |
| 1041 case Position::PositionIsAfterAnchor: | 1046 case Position::PositionIsAfterAnchor: |
| 1042 if (node->containsIncludingShadowDOM(position.anchorNode())) | 1047 if (node->containsIncludingShadowDOM(position.anchorNode())) |
| 1043 position = positionInParentAfterNode(adoptRawResult(node)); | 1048 position = positionInParentAfterNode(node); |
| 1044 break; | 1049 break; |
| 1045 case Position::PositionIsBeforeAnchor: | 1050 case Position::PositionIsBeforeAnchor: |
| 1046 if (node->containsIncludingShadowDOM(position.anchorNode())) | 1051 if (node->containsIncludingShadowDOM(position.anchorNode())) |
| 1047 position = positionInParentBeforeNode(adoptRawResult(node)); | 1052 position = positionInParentBeforeNode(node); |
| 1048 break; | 1053 break; |
| 1049 } | 1054 } |
| 1050 } | 1055 } |
| 1051 | 1056 |
| 1052 bool isMailBlockquote(const Node *node) | 1057 bool isMailBlockquote(const Handle<const Node>& node) |
| 1053 { | 1058 { |
| 1054 if (!node || !node->hasTagName(blockquoteTag)) | 1059 if (!node || !node->hasTagName(blockquoteTag)) |
| 1055 return false; | 1060 return false; |
| 1056 | 1061 |
| 1057 return static_cast<const Element *>(node)->getAttribute("type") == "cite"; | 1062 return Handle<const Element>::cast(node)->getAttribute("type") == "cite"; |
| 1058 } | 1063 } |
| 1059 | 1064 |
| 1060 int caretMinOffset(const Node* n) | 1065 int caretMinOffset(const Handle<const Node>& n) |
| 1061 { | 1066 { |
| 1062 RenderObject* r = n->renderer(); | 1067 RenderObject* r = n->renderer(); |
| 1063 ASSERT(!n->isCharacterDataNode() || !r || r->isText()); // FIXME: This was a
runtime check that seemingly couldn't fail; changed it to an assertion for now. | 1068 ASSERT(!n->isCharacterDataNode() || !r || r->isText()); // FIXME: This was a
runtime check that seemingly couldn't fail; changed it to an assertion for now. |
| 1064 return r ? r->caretMinOffset() : 0; | 1069 return r ? r->caretMinOffset() : 0; |
| 1065 } | 1070 } |
| 1066 | 1071 |
| 1067 // If a node can contain candidates for VisiblePositions, return the offset of t
he last candidate, otherwise | 1072 // If a node can contain candidates for VisiblePositions, return the offset of t
he last candidate, otherwise |
| 1068 // return the number of children for container nodes and the length for unrender
ed text nodes. | 1073 // return the number of children for container nodes and the length for unrender
ed text nodes. |
| 1069 int caretMaxOffset(const Node* n) | 1074 int caretMaxOffset(const Handle<const Node>& n) |
| 1070 { | 1075 { |
| 1071 // For rendered text nodes, return the last position that a caret could occu
py. | 1076 // For rendered text nodes, return the last position that a caret could occu
py. |
| 1072 if (n->isTextNode() && n->renderer()) | 1077 if (n->isTextNode() && n->renderer()) |
| 1073 return n->renderer()->caretMaxOffset(); | 1078 return n->renderer()->caretMaxOffset(); |
| 1074 // For containers return the number of children. For others do the same as a
bove. | 1079 // For containers return the number of children. For others do the same as a
bove. |
| 1075 return lastOffsetForEditing(n); | 1080 return lastOffsetForEditing(n); |
| 1076 } | 1081 } |
| 1077 | 1082 |
| 1078 bool lineBreakExistsAtVisiblePosition(const VisiblePosition& visiblePosition) | 1083 bool lineBreakExistsAtVisiblePosition(const VisiblePosition& visiblePosition) |
| 1079 { | 1084 { |
| (...skipping 25 matching lines...) Expand all Loading... |
| 1105 VisibleSelection selectionForParagraphIteration(const VisibleSelection& original
) | 1110 VisibleSelection selectionForParagraphIteration(const VisibleSelection& original
) |
| 1106 { | 1111 { |
| 1107 VisibleSelection newSelection(original); | 1112 VisibleSelection newSelection(original); |
| 1108 VisiblePosition startOfSelection(newSelection.visibleStart()); | 1113 VisiblePosition startOfSelection(newSelection.visibleStart()); |
| 1109 VisiblePosition endOfSelection(newSelection.visibleEnd()); | 1114 VisiblePosition endOfSelection(newSelection.visibleEnd()); |
| 1110 | 1115 |
| 1111 // If the end of the selection to modify is just after a table, and | 1116 // If the end of the selection to modify is just after a table, and |
| 1112 // if the start of the selection is inside that table, then the last paragra
ph | 1117 // if the start of the selection is inside that table, then the last paragra
ph |
| 1113 // that we'll want modify is the last one inside the table, not the table it
self | 1118 // that we'll want modify is the last one inside the table, not the table it
self |
| 1114 // (a table is itself a paragraph). | 1119 // (a table is itself a paragraph). |
| 1115 if (Node* table = isFirstPositionAfterTable(endOfSelection)) | 1120 if (Handle<Node> table = isFirstPositionAfterTable(endOfSelection)) |
| 1116 if (startOfSelection.deepEquivalent().deprecatedNode()->isDescendantOf(t
able)) | 1121 if (startOfSelection.deepEquivalent().deprecatedNode()->isDescendantOf(t
able.raw())) |
| 1117 newSelection = VisibleSelection(startOfSelection, endOfSelection.pre
vious(CannotCrossEditingBoundary)); | 1122 newSelection = VisibleSelection(startOfSelection, endOfSelection.pre
vious(CannotCrossEditingBoundary)); |
| 1118 | 1123 |
| 1119 // If the start of the selection to modify is just before a table, | 1124 // If the start of the selection to modify is just before a table, |
| 1120 // and if the end of the selection is inside that table, then the first para
graph | 1125 // and if the end of the selection is inside that table, then the first para
graph |
| 1121 // we'll want to modify is the first one inside the table, not the paragraph | 1126 // we'll want to modify is the first one inside the table, not the paragraph |
| 1122 // containing the table itself. | 1127 // containing the table itself. |
| 1123 if (Node* table = isLastPositionBeforeTable(startOfSelection)) | 1128 if (Handle<Node> table = isLastPositionBeforeTable(startOfSelection)) |
| 1124 if (endOfSelection.deepEquivalent().deprecatedNode()->isDescendantOf(tab
le)) | 1129 if (endOfSelection.deepEquivalent().deprecatedNode()->isDescendantOf(tab
le.raw())) |
| 1125 newSelection = VisibleSelection(startOfSelection.next(CannotCrossEdi
tingBoundary), endOfSelection); | 1130 newSelection = VisibleSelection(startOfSelection.next(CannotCrossEdi
tingBoundary), endOfSelection); |
| 1126 | 1131 |
| 1127 return newSelection; | 1132 return newSelection; |
| 1128 } | 1133 } |
| 1129 | 1134 |
| 1130 // FIXME: indexForVisiblePosition and visiblePositionForIndex use TextIterators
to convert between | 1135 // FIXME: indexForVisiblePosition and visiblePositionForIndex use TextIterators
to convert between |
| 1131 // VisiblePositions and indices. But TextIterator iteration using TextIteratorEm
itsCharactersBetweenAllVisiblePositions | 1136 // VisiblePositions and indices. But TextIterator iteration using TextIteratorEm
itsCharactersBetweenAllVisiblePositions |
| 1132 // does not exactly match VisiblePosition iteration, so using them to preserve a
selection during an editing | 1137 // does not exactly match VisiblePosition iteration, so using them to preserve a
selection during an editing |
| 1133 // opertion is unreliable. TextIterator's TextIteratorEmitsCharactersBetweenAllV
isiblePositions mode needs to be fixed, | 1138 // opertion is unreliable. TextIterator's TextIteratorEmitsCharactersBetweenAllV
isiblePositions mode needs to be fixed, |
| 1134 // or these functions need to be changed to iterate using actual VisiblePosition
s. | 1139 // or these functions need to be changed to iterate using actual VisiblePosition
s. |
| (...skipping 29 matching lines...) Expand all Loading... |
| 1164 | 1169 |
| 1165 // Determines whether two positions are visibly next to each other (first then s
econd) | 1170 // Determines whether two positions are visibly next to each other (first then s
econd) |
| 1166 // while ignoring whitespaces and unrendered nodes | 1171 // while ignoring whitespaces and unrendered nodes |
| 1167 bool isVisiblyAdjacent(const Position& first, const Position& second) | 1172 bool isVisiblyAdjacent(const Position& first, const Position& second) |
| 1168 { | 1173 { |
| 1169 return VisiblePosition(first) == VisiblePosition(second.upstream()); | 1174 return VisiblePosition(first) == VisiblePosition(second.upstream()); |
| 1170 } | 1175 } |
| 1171 | 1176 |
| 1172 // Determines whether a node is inside a range or visibly starts and ends at the
boundaries of the range. | 1177 // Determines whether a node is inside a range or visibly starts and ends at the
boundaries of the range. |
| 1173 // Call this function to determine whether a node is visibly fit inside selected
Range | 1178 // Call this function to determine whether a node is visibly fit inside selected
Range |
| 1174 bool isNodeVisiblyContainedWithin(Node* node, const Handle<const Range>& selecte
dRange) | 1179 bool isNodeVisiblyContainedWithin(const Handle<Node>& node, const Handle<const R
ange>& selectedRange) |
| 1175 { | 1180 { |
| 1176 ASSERT(node); | 1181 ASSERT(node); |
| 1177 ASSERT(selectedRange); | 1182 ASSERT(selectedRange); |
| 1178 // If the node is inside the range, then it surely is contained within | 1183 // If the node is inside the range, then it surely is contained within |
| 1179 if (selectedRange->compareNode(adoptRawResult(node), IGNORE_EXCEPTION) == Ra
nge::NODE_INSIDE) | 1184 if (selectedRange->compareNode(node, IGNORE_EXCEPTION) == Range::NODE_INSIDE
) |
| 1180 return true; | 1185 return true; |
| 1181 | 1186 |
| 1182 bool startIsVisuallySame = visiblePositionBeforeNode(node) == selectedRange-
>startPosition(); | 1187 bool startIsVisuallySame = visiblePositionBeforeNode(node) == selectedRange-
>startPosition(); |
| 1183 if (startIsVisuallySame && comparePositions(positionInParentAfterNode(adoptR
awResult(node)), selectedRange->endPosition()) < 0) | 1188 if (startIsVisuallySame && comparePositions(positionInParentAfterNode(node),
selectedRange->endPosition()) < 0) |
| 1184 return true; | 1189 return true; |
| 1185 | 1190 |
| 1186 bool endIsVisuallySame = visiblePositionAfterNode(node) == selectedRange->en
dPosition(); | 1191 bool endIsVisuallySame = visiblePositionAfterNode(node) == selectedRange->en
dPosition(); |
| 1187 if (endIsVisuallySame && comparePositions(selectedRange->startPosition(), po
sitionInParentBeforeNode(adoptRawResult(node))) < 0) | 1192 if (endIsVisuallySame && comparePositions(selectedRange->startPosition(), po
sitionInParentBeforeNode(node)) < 0) |
| 1188 return true; | 1193 return true; |
| 1189 | 1194 |
| 1190 return startIsVisuallySame && endIsVisuallySame; | 1195 return startIsVisuallySame && endIsVisuallySame; |
| 1191 } | 1196 } |
| 1192 | 1197 |
| 1193 bool isRenderedAsNonInlineTableImageOrHR(const Node* node) | 1198 bool isRenderedAsNonInlineTableImageOrHR(const Handle<const Node>& node) |
| 1194 { | 1199 { |
| 1195 if (!node) | 1200 if (!node) |
| 1196 return false; | 1201 return false; |
| 1197 RenderObject* renderer = node->renderer(); | 1202 RenderObject* renderer = node->renderer(); |
| 1198 return renderer && ((renderer->isTable() && !renderer->isInline()) || (rende
rer->isImage() && !renderer->isInline()) || renderer->isHR()); | 1203 return renderer && ((renderer->isTable() && !renderer->isInline()) || (rende
rer->isImage() && !renderer->isInline()) || renderer->isHR()); |
| 1199 } | 1204 } |
| 1200 | 1205 |
| 1201 bool areIdenticalElements(const Node* first, const Node* second) | 1206 bool areIdenticalElements(const Handle<const Node>& first, const Handle<const No
de>& second) |
| 1202 { | 1207 { |
| 1203 if (!first->isElementNode() || !second->isElementNode()) | 1208 if (!first->isElementNode() || !second->isElementNode()) |
| 1204 return false; | 1209 return false; |
| 1205 | 1210 |
| 1206 Handle<const Element> firstElement = adoptRawResult(toElement(first)); | 1211 Handle<const Element> firstElement = toConstElement(first); |
| 1207 Handle<const Element> secondElement = adoptRawResult(toElement(second)); | 1212 Handle<const Element> secondElement = toConstElement(second); |
| 1208 if (!firstElement->hasTagName(secondElement->tagQName())) | 1213 if (!firstElement->hasTagName(secondElement->tagQName())) |
| 1209 return false; | 1214 return false; |
| 1210 | 1215 |
| 1211 return firstElement->hasEquivalentAttributes(secondElement); | 1216 return firstElement->hasEquivalentAttributes(secondElement); |
| 1212 } | 1217 } |
| 1213 | 1218 |
| 1214 bool isNonTableCellHTMLBlockElement(const Node* node) | 1219 bool isNonTableCellHTMLBlockElement(const Handle<const Node>& node) |
| 1215 { | 1220 { |
| 1216 return node->hasTagName(listingTag) | 1221 return node->hasTagName(listingTag) |
| 1217 || node->hasTagName(olTag) | 1222 || node->hasTagName(olTag) |
| 1218 || node->hasTagName(preTag) | 1223 || node->hasTagName(preTag) |
| 1219 || node->hasTagName(tableTag) | 1224 || node->hasTagName(tableTag) |
| 1220 || node->hasTagName(ulTag) | 1225 || node->hasTagName(ulTag) |
| 1221 || node->hasTagName(xmpTag) | 1226 || node->hasTagName(xmpTag) |
| 1222 || node->hasTagName(h1Tag) | 1227 || node->hasTagName(h1Tag) |
| 1223 || node->hasTagName(h2Tag) | 1228 || node->hasTagName(h2Tag) |
| 1224 || node->hasTagName(h3Tag) | 1229 || node->hasTagName(h3Tag) |
| (...skipping 20 matching lines...) Expand all Loading... |
| 1245 // if the selection starts just before a paragraph break, skip over it | 1250 // if the selection starts just before a paragraph break, skip over it |
| 1246 if (isEndOfParagraph(visiblePosition)) | 1251 if (isEndOfParagraph(visiblePosition)) |
| 1247 return visiblePosition.next().deepEquivalent().downstream(); | 1252 return visiblePosition.next().deepEquivalent().downstream(); |
| 1248 | 1253 |
| 1249 // otherwise, make sure to be at the start of the first selected node, | 1254 // otherwise, make sure to be at the start of the first selected node, |
| 1250 // instead of possibly at the end of the last node before the selection | 1255 // instead of possibly at the end of the last node before the selection |
| 1251 return visiblePosition.deepEquivalent().downstream(); | 1256 return visiblePosition.deepEquivalent().downstream(); |
| 1252 } | 1257 } |
| 1253 | 1258 |
| 1254 } // namespace WebCore | 1259 } // namespace WebCore |
| OLD | NEW |