Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(104)

Side by Side Diff: Source/core/editing/InsertListCommand.cpp

Issue 24278008: [oilpan] Handlify Nodes in htmlediting (Closed) Base URL: svn://svn.chromium.org/blink/branches/oilpan
Patch Set: Created 7 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 /* 1 /*
2 * Copyright (C) 2006, 2010 Apple Inc. All rights reserved. 2 * Copyright (C) 2006, 2010 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 22 matching lines...) Expand all
33 #include "core/editing/VisibleUnits.h" 33 #include "core/editing/VisibleUnits.h"
34 #include "core/editing/htmlediting.h" 34 #include "core/editing/htmlediting.h"
35 #include "core/html/HTMLElement.h" 35 #include "core/html/HTMLElement.h"
36 36
37 namespace WebCore { 37 namespace WebCore {
38 38
39 using namespace HTMLNames; 39 using namespace HTMLNames;
40 40
41 static Node* enclosingListChild(Node* node, Node* listNode) 41 static Node* enclosingListChild(Node* node, Node* listNode)
42 { 42 {
43 Node* listChild = enclosingListChild(node); 43 Handle<Node> listChild = enclosingListChild(adoptRawResult(node));
44 while (listChild && enclosingList(listChild) != listNode) { 44 while (listChild && enclosingList(listChild) != listNode) {
45 HandleScope scope; 45 HandleScope scope;
46 listChild = enclosingListChild(listChild->parentNode().handle().raw()); 46 listChild = enclosingListChild(listChild->parentNode());
47 } 47 }
48 return listChild; 48 return listChild.raw();
49 } 49 }
50 50
51 Result<HTMLElement> InsertListCommand::insertList(const Handle<Document>& docume nt, Type type) 51 Result<HTMLElement> InsertListCommand::insertList(const Handle<Document>& docume nt, Type type)
52 { 52 {
53 RefPtr<InsertListCommand> insertCommand = create(document, type); 53 RefPtr<InsertListCommand> insertCommand = create(document, type);
54 insertCommand->apply(); 54 insertCommand->apply();
55 return insertCommand->m_listElement; 55 return insertCommand->m_listElement;
56 } 56 }
57 57
58 Result<HTMLElement> InsertListCommand::fixOrphanedListChild(Node* node) 58 Result<HTMLElement> InsertListCommand::fixOrphanedListChild(Node* node)
(...skipping 20 matching lines...) Expand all
79 mergeIdenticalElements(list, nextList); 79 mergeIdenticalElements(list, nextList);
80 return nextList; 80 return nextList;
81 } 81 }
82 return list; 82 return list;
83 } 83 }
84 84
85 bool InsertListCommand::selectionHasListOfType(const VisibleSelection& selection , const QualifiedName& listTag) 85 bool InsertListCommand::selectionHasListOfType(const VisibleSelection& selection , const QualifiedName& listTag)
86 { 86 {
87 VisiblePosition start = selection.visibleStart(); 87 VisiblePosition start = selection.visibleStart();
88 88
89 if (!enclosingList(start.deepEquivalent().deprecatedNode().handle().raw())) 89 if (!enclosingList(start.deepEquivalent().deprecatedNode()))
90 return false; 90 return false;
91 91
92 VisiblePosition end = startOfParagraph(selection.visibleEnd()); 92 VisiblePosition end = startOfParagraph(selection.visibleEnd());
93 while (start.isNotNull() && start != end) { 93 while (start.isNotNull() && start != end) {
94 HandleScope scope; 94 HandleScope scope;
95 Handle<Element> listNode = enclosingList(start.deepEquivalent().deprecat edNode().handle().raw()); 95 Handle<Element> listNode = enclosingList(start.deepEquivalent().deprecat edNode());
96 if (!listNode || !listNode->hasTagName(listTag)) 96 if (!listNode || !listNode->hasTagName(listTag))
97 return false; 97 return false;
98 start = startOfNextParagraph(start); 98 start = startOfNextParagraph(start);
99 } 99 }
100 100
101 return true; 101 return true;
102 } 102 }
103 103
104 InsertListCommand::InsertListCommand(const Handle<Document>& document, Type type ) 104 InsertListCommand::InsertListCommand(const Handle<Document>& document, Type type )
105 : CompositeEditCommand(document), m_type(type) 105 : CompositeEditCommand(document), m_type(type)
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after
189 189
190 doApplyForSingleParagraph(false, listTag, endingSelection().firstRange()); 190 doApplyForSingleParagraph(false, listTag, endingSelection().firstRange());
191 } 191 }
192 192
193 void InsertListCommand::doApplyForSingleParagraph(bool forceCreateList, const Qu alifiedName& listTag, const Handle<Range>& currentSelection) 193 void InsertListCommand::doApplyForSingleParagraph(bool forceCreateList, const Qu alifiedName& listTag, const Handle<Range>& currentSelection)
194 { 194 {
195 // FIXME: This will produce unexpected results for a selection that starts j ust before a 195 // FIXME: This will produce unexpected results for a selection that starts j ust before a
196 // table and ends inside the first cell, selectionForParagraphIteration shou ld probably 196 // table and ends inside the first cell, selectionForParagraphIteration shou ld probably
197 // be renamed and deployed inside setEndingSelection(). 197 // be renamed and deployed inside setEndingSelection().
198 Handle<Node> selectionNode = endingSelection().start().deprecatedNode(); 198 Handle<Node> selectionNode = endingSelection().start().deprecatedNode();
199 Node* listChildNode = enclosingListChild(selectionNode.raw()); 199 Handle<Node> listChildNode = enclosingListChild(selectionNode);
200 bool switchListType = false; 200 bool switchListType = false;
201 if (listChildNode) { 201 if (listChildNode) {
202 // Remove the list chlild. 202 // Remove the list chlild.
203 Handle<HTMLElement> listNode = enclosingList(listChildNode); 203 Handle<HTMLElement> listNode = enclosingList(listChildNode);
204 if (!listNode) { 204 if (!listNode) {
205 listNode = fixOrphanedListChild(listChildNode); 205 listNode = fixOrphanedListChild(listChildNode.raw());
206 listNode = mergeWithNeighboringLists(listNode); 206 listNode = mergeWithNeighboringLists(listNode);
207 } 207 }
208 if (!listNode->hasTagName(listTag)) 208 if (!listNode->hasTagName(listTag))
209 // listChildNode will be removed from the list and a list of type m_ type will be created. 209 // listChildNode will be removed from the list and a list of type m_ type will be created.
210 switchListType = true; 210 switchListType = true;
211 211
212 // If the list is of the desired type, and we are not removing the list, then exit early. 212 // If the list is of the desired type, and we are not removing the list, then exit early.
213 if (!switchListType && forceCreateList) 213 if (!switchListType && forceCreateList)
214 return; 214 return;
215 215
216 // If the entire list is selected, then convert the whole list. 216 // If the entire list is selected, then convert the whole list.
217 if (switchListType && isNodeVisiblyContainedWithin(listNode.raw(), curre ntSelection)) { 217 if (switchListType && isNodeVisiblyContainedWithin(listNode, currentSele ction)) {
218 bool rangeStartIsInList = visiblePositionBeforeNode(listNode.raw()) == currentSelection->startPosition(); 218 bool rangeStartIsInList = visiblePositionBeforeNode(listNode) == cur rentSelection->startPosition();
219 bool rangeEndIsInList = visiblePositionAfterNode(listNode.raw()) == currentSelection->endPosition(); 219 bool rangeEndIsInList = visiblePositionAfterNode(listNode) == curren tSelection->endPosition();
220 220
221 Handle<HTMLElement> newList = createHTMLElement(document(), listTag) ; 221 Handle<HTMLElement> newList = createHTMLElement(document(), listTag) ;
222 insertNodeBefore(newList, listNode); 222 insertNodeBefore(newList, listNode);
223 223
224 Handle<Node> firstChildInList = adoptRawResult(enclosingListChild(Vi siblePosition(firstPositionInNode(listNode)).deepEquivalent().deprecatedNode().h andle().raw(), listNode.raw())); 224 Handle<Node> firstChildInList = adoptRawResult(enclosingListChild(Vi siblePosition(firstPositionInNode(listNode)).deepEquivalent().deprecatedNode().h andle().raw(), listNode.raw()));
225 Handle<Node> outerBlock = firstChildInList->isBlockFlowElement() ? f irstChildInList : Handle<Node>(listNode); 225 Handle<Node> outerBlock = firstChildInList->isBlockFlowElement() ? f irstChildInList : Handle<Node>(listNode);
226 moveParagraphWithClones(firstPositionInNode(listNode), lastPositionI nNode(listNode), newList, outerBlock); 226 moveParagraphWithClones(firstPositionInNode(listNode), lastPositionI nNode(listNode), newList, outerBlock);
227 227
228 // Manually remove listNode because moveParagraphWithClones sometime s leaves it behind in the document. 228 // Manually remove listNode because moveParagraphWithClones sometime s leaves it behind in the document.
229 // See the bug 33668 and editing/execCommand/insert-list-orphaned-it em-with-nested-lists.html. 229 // See the bug 33668 and editing/execCommand/insert-list-orphaned-it em-with-nested-lists.html.
230 // FIXME: This might be a bug in moveParagraphWithClones or deleteSe lection. 230 // FIXME: This might be a bug in moveParagraphWithClones or deleteSe lection.
231 if (listNode && listNode->inDocument()) 231 if (listNode && listNode->inDocument())
232 removeNode(listNode); 232 removeNode(listNode);
233 233
234 newList = mergeWithNeighboringLists(newList); 234 newList = mergeWithNeighboringLists(newList);
235 235
236 // Restore the start and the end of current selection if they starte d inside listNode 236 // Restore the start and the end of current selection if they starte d inside listNode
237 // because moveParagraphWithClones could have removed them. 237 // because moveParagraphWithClones could have removed them.
238 if (rangeStartIsInList && newList) 238 if (rangeStartIsInList && newList)
239 currentSelection->setStart(newList, 0, IGNORE_EXCEPTION); 239 currentSelection->setStart(newList, 0, IGNORE_EXCEPTION);
240 if (rangeEndIsInList && newList) 240 if (rangeEndIsInList && newList)
241 currentSelection->setEnd(newList, lastOffsetInNode(newList), IGN ORE_EXCEPTION); 241 currentSelection->setEnd(newList, lastOffsetInNode(newList), IGN ORE_EXCEPTION);
242 242
243 setEndingSelection(VisiblePosition(firstPositionInNode(newList))); 243 setEndingSelection(VisiblePosition(firstPositionInNode(newList)));
244 244
245 return; 245 return;
246 } 246 }
247 247
248 unlistifyParagraph(endingSelection().visibleStart(), listNode, listChild Node); 248 unlistifyParagraph(endingSelection().visibleStart(), listNode, listChild Node.raw());
249 } 249 }
250 250
251 if (!listChildNode || switchListType || forceCreateList) 251 if (!listChildNode || switchListType || forceCreateList)
252 m_listElement = listifyParagraph(endingSelection().visibleStart(), listT ag); 252 m_listElement = listifyParagraph(endingSelection().visibleStart(), listT ag);
253 } 253 }
254 254
255 void InsertListCommand::unlistifyParagraph(const VisiblePosition& originalStart, const Handle<HTMLElement>& listNode, Node* listChildNode) 255 void InsertListCommand::unlistifyParagraph(const VisiblePosition& originalStart, const Handle<HTMLElement>& listNode, Node* listChildNode)
256 { 256 {
257 Node* nextListChild; 257 Node* nextListChild;
258 Node* previousListChild; 258 Node* previousListChild;
(...skipping 12 matching lines...) Expand all
271 ASSERT(nextListChild != listChildNode); 271 ASSERT(nextListChild != listChildNode);
272 previousListChild = enclosingListChild(start.previous().deepEquivalent() .deprecatedNode().handle().raw(), listNode.raw()); 272 previousListChild = enclosingListChild(start.previous().deepEquivalent() .deprecatedNode().handle().raw(), listNode.raw());
273 ASSERT(previousListChild != listChildNode); 273 ASSERT(previousListChild != listChildNode);
274 } 274 }
275 // When removing a list, we must always create a placeholder to act as a poi nt of insertion 275 // When removing a list, we must always create a placeholder to act as a poi nt of insertion
276 // for the list content being removed. 276 // for the list content being removed.
277 Handle<Element> placeholder = createBreakElement(document()); 277 Handle<Element> placeholder = createBreakElement(document());
278 Handle<Element> nodeToInsert = placeholder; 278 Handle<Element> nodeToInsert = placeholder;
279 // If the content of the list item will be moved into another list, put it i n a list item 279 // If the content of the list item will be moved into another list, put it i n a list item
280 // so that we don't create an orphaned list child. 280 // so that we don't create an orphaned list child.
281 if (enclosingList(listNode.raw())) { 281 if (enclosingList(listNode)) {
282 nodeToInsert = createListItemElement(document()); 282 nodeToInsert = createListItemElement(document());
283 appendNode(placeholder, nodeToInsert); 283 appendNode(placeholder, nodeToInsert);
284 } 284 }
285 285
286 if (nextListChild && previousListChild) { 286 if (nextListChild && previousListChild) {
287 // We want to pull listChildNode out of listNode, and place it before ne xtListChild 287 // We want to pull listChildNode out of listNode, and place it before ne xtListChild
288 // and after previousListChild, so we split listNode and insert it betwe en the two lists. 288 // and after previousListChild, so we split listNode and insert it betwe en the two lists.
289 // But to split listNode, we must first split ancestors of listChildNode between it and listNode, 289 // But to split listNode, we must first split ancestors of listChildNode between it and listNode,
290 // if any exist. 290 // if any exist.
291 // FIXME: We appear to split at nextListChild as opposed to listChildNod e so that when we remove 291 // FIXME: We appear to split at nextListChild as opposed to listChildNod e so that when we remove
(...skipping 11 matching lines...) Expand all
303 insertNodeBefore(nodeToInsert, listNode); 303 insertNodeBefore(nodeToInsert, listNode);
304 } else 304 } else
305 insertNodeAfter(nodeToInsert, listNode); 305 insertNodeAfter(nodeToInsert, listNode);
306 306
307 VisiblePosition insertionPoint = VisiblePosition(positionBeforeNode(placehol der)); 307 VisiblePosition insertionPoint = VisiblePosition(positionBeforeNode(placehol der));
308 moveParagraphs(start, end, insertionPoint, /* preserveSelection */ true, /* preserveStyle */ true, adoptRawResult(listChildNode)); 308 moveParagraphs(start, end, insertionPoint, /* preserveSelection */ true, /* preserveStyle */ true, adoptRawResult(listChildNode));
309 } 309 }
310 310
311 static Result<Element> adjacentEnclosingList(const VisiblePosition& pos, const V isiblePosition& adjacentPos, const QualifiedName& listTag) 311 static Result<Element> adjacentEnclosingList(const VisiblePosition& pos, const V isiblePosition& adjacentPos, const QualifiedName& listTag)
312 { 312 {
313 Handle<Element> listNode = outermostEnclosingList(adjacentPos.deepEquivalent ().deprecatedNode().handle().raw()); 313 Handle<Element> listNode = outermostEnclosingList(adjacentPos.deepEquivalent ().deprecatedNode());
314 if (!listNode) 314 if (!listNode)
315 return nullptr; 315 return nullptr;
316 316
317 Node* previousCell = enclosingTableCell(pos.deepEquivalent()); 317 Handle<Node> previousCell = enclosingTableCell(pos.deepEquivalent());
318 Node* currentCell = enclosingTableCell(adjacentPos.deepEquivalent()); 318 Handle<Node> currentCell = enclosingTableCell(adjacentPos.deepEquivalent());
319 319
320 if (!listNode->hasTagName(listTag) 320 if (!listNode->hasTagName(listTag)
321 || listNode->contains(pos.deepEquivalent().deprecatedNode()) 321 || listNode->contains(pos.deepEquivalent().deprecatedNode())
322 || previousCell != currentCell 322 || previousCell != currentCell
323 || enclosingList(listNode.raw()) != enclosingList(pos.deepEquivalent().d eprecatedNode().handle().raw())) 323 || enclosingList(listNode) != enclosingList(pos.deepEquivalent().depreca tedNode()))
324 return nullptr; 324 return nullptr;
325 325
326 return listNode; 326 return listNode;
327 } 327 }
328 328
329 Result<HTMLElement> InsertListCommand::listifyParagraph(const VisiblePosition& o riginalStart, const QualifiedName& listTag) 329 Result<HTMLElement> InsertListCommand::listifyParagraph(const VisiblePosition& o riginalStart, const QualifiedName& listTag)
330 { 330 {
331 VisiblePosition start = startOfParagraph(originalStart, CanSkipOverEditingBo undary); 331 VisiblePosition start = startOfParagraph(originalStart, CanSkipOverEditingBo undary);
332 VisiblePosition end = endOfParagraph(start, CanSkipOverEditingBoundary); 332 VisiblePosition end = endOfParagraph(start, CanSkipOverEditingBoundary);
333 333
(...skipping 11 matching lines...) Expand all
345 Handle<HTMLElement> listElement; 345 Handle<HTMLElement> listElement;
346 if (previousList) 346 if (previousList)
347 appendNode(listItemElement, previousList); 347 appendNode(listItemElement, previousList);
348 else if (nextList) 348 else if (nextList)
349 insertNodeAt(listItemElement, positionBeforeNode(nextList)); 349 insertNodeAt(listItemElement, positionBeforeNode(nextList));
350 else { 350 else {
351 // Create the list. 351 // Create the list.
352 listElement = createHTMLElement(document(), listTag); 352 listElement = createHTMLElement(document(), listTag);
353 appendNode(listItemElement, listElement); 353 appendNode(listItemElement, listElement);
354 354
355 if (start == end && isBlock(start.deepEquivalent().deprecatedNode().hand le().raw())) { 355 if (start == end && isBlock(start.deepEquivalent().deprecatedNode())) {
356 // Inserting the list into an empty paragraph that isn't held open 356 // Inserting the list into an empty paragraph that isn't held open
357 // by a br or a '\n', will invalidate start and end. Insert 357 // by a br or a '\n', will invalidate start and end. Insert
358 // a placeholder and then recompute start and end. 358 // a placeholder and then recompute start and end.
359 Handle<Node> placeholder = insertBlockPlaceholder(start.deepEquivale nt()); 359 Handle<Node> placeholder = insertBlockPlaceholder(start.deepEquivale nt());
360 start = positionBeforeNode(placeholder); 360 start = positionBeforeNode(placeholder);
361 end = start; 361 end = start;
362 } 362 }
363 363
364 // Insert the list at a position visually equivalent to start of the 364 // Insert the list at a position visually equivalent to start of the
365 // paragraph that is being moved into the list. 365 // paragraph that is being moved into the list.
366 // Try to avoid inserting it somewhere where it will be surrounded by 366 // Try to avoid inserting it somewhere where it will be surrounded by
367 // inline ancestors of start, since it is easier for editing to produce 367 // inline ancestors of start, since it is easier for editing to produce
368 // clean markup when inline elements are pushed down as far as possible. 368 // clean markup when inline elements are pushed down as far as possible.
369 Position insertionPos(start.deepEquivalent().upstream()); 369 Position insertionPos(start.deepEquivalent().upstream());
370 // Also avoid the containing list item. 370 // Also avoid the containing list item.
371 Handle<Node> listChild = adoptRawResult(enclosingListChild(insertionPos. deprecatedNode().handle().raw())); 371 Handle<Node> listChild = enclosingListChild(insertionPos.deprecatedNode( ));
372 if (listChild && listChild->hasTagName(liTag)) 372 if (listChild && listChild->hasTagName(liTag))
373 insertionPos = positionInParentBeforeNode(listChild); 373 insertionPos = positionInParentBeforeNode(listChild);
374 374
375 insertNodeAt(listElement, insertionPos); 375 insertNodeAt(listElement, insertionPos);
376 376
377 // We inserted the list at the start of the content we're about to move 377 // We inserted the list at the start of the content we're about to move
378 // Update the start of content, so we don't try to move the list into it self. bug 19066 378 // Update the start of content, so we don't try to move the list into it self. bug 19066
379 // Layout is necessary since start's node's inline renderers may have be en destroyed by the insertion 379 // Layout is necessary since start's node's inline renderers may have be en destroyed by the insertion
380 // The end of the content may have changed after the insertion and layou t so update it as well. 380 // The end of the content may have changed after the insertion and layou t so update it as well.
381 if (insertionPos == start.deepEquivalent()) { 381 if (insertionPos == start.deepEquivalent()) {
382 listElement->document()->updateLayoutIgnorePendingStylesheets(); 382 listElement->document()->updateLayoutIgnorePendingStylesheets();
383 start = startOfParagraph(originalStart, CanSkipOverEditingBoundary); 383 start = startOfParagraph(originalStart, CanSkipOverEditingBoundary);
384 end = endOfParagraph(start, CanSkipOverEditingBoundary); 384 end = endOfParagraph(start, CanSkipOverEditingBoundary);
385 } 385 }
386 } 386 }
387 387
388 moveParagraph(start, end, positionBeforeNode(placeholder), true); 388 moveParagraph(start, end, positionBeforeNode(placeholder), true);
389 389
390 if (listElement) 390 if (listElement)
391 return mergeWithNeighboringLists(listElement); 391 return mergeWithNeighboringLists(listElement);
392 392
393 if (canMergeLists(previousList, nextList)) 393 if (canMergeLists(previousList, nextList))
394 mergeIdenticalElements(previousList, nextList); 394 mergeIdenticalElements(previousList, nextList);
395 395
396 return listElement; 396 return listElement;
397 } 397 }
398 398
399 } 399 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698