Changeset 12789 in webkit
- Timestamp:
- Feb 13, 2006 7:29:43 PM (18 years ago)
- Location:
- trunk/WebCore
- Files:
-
- 8 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/WebCore/ChangeLog
r12788 r12789 1 2006-02-07 David Harrison <harrison@apple.com> 2 3 Reviewed by Justin. 4 5 - merge VisiblePosition:isCandidate() into Position::inRenderedContent() 6 These functions were answering the same question in different ways! We 7 only need one implementation. 8 9 * khtml/editing/visible_position.cpp: 10 (khtml::VisiblePosition::init): 11 (khtml::VisiblePosition::previousVisiblePosition): 12 (khtml::VisiblePosition::nextVisiblePosition): 13 (khtml::VisiblePosition::deepEquivalent): 14 * khtml/editing/visible_position.h: 15 * dom/dom_position.cpp: 16 (DOM::hasRenderedChildrenWithHeight): 17 (DOM::Position::inRenderedContent): 18 19 20 - improved table deletion. 21 Fixes: delete back by word from just after table did not delete the table 22 delete forward by char or word did not delete the table 23 deleting back to a table and again did not delete the table 24 25 * khtml/editing/htmlediting.cpp: 26 (WebCore::isFirstVisiblePositionAfterTableElement): 27 simpler implementation 28 (WebCore::positionBeforePrecedingTableElement): 29 simpler implementation 30 (WebCore::isFirstVisiblePositionBeforeTableElement): 31 new 32 (WebCore::positionAfterFollowingTableElement): 33 new 34 * khtml/editing/htmlediting.h: 35 * khtml/editing/SelectionController.cpp: 36 (WebCore::SelectionController::modifyExtendingRightForward): 37 select following table if granularity is char or word 38 (WebCore::SelectionController::modifyExtendingLeftBackward): 39 select preceding table if granularity is char or word 40 * khtml/editing/typing_command.cpp: 41 (khtml::TypingCommand::deleteKeyPressed): 42 simpler implementation, and let other deleteKeyPressed do boundary checking 43 (khtml::TypingCommand::forwardDeleteKeyPressed): 44 simpler implementation, and let other forwardDeleteKeyPressed do boundary checking 45 (khtml::TypingCommand::insertText): 46 standard formatting 47 (khtml::TypingCommand::insertLineBreak): 48 standard formatting 49 (khtml::TypingCommand::insertParagraphSeparatorInQuotedContent): 50 standard formatting 51 (khtml::TypingCommand::insertParagraphSeparator): 52 standard formatting 53 (khtml::TypingCommand::insertTextRunWithoutNewlines): 54 standard formatting 55 (khtml::TypingCommand::deleteKeyPressed): 56 use SelectionController to extend selection, to get all the selection 57 logic incl. table selection and editable/noneditable boundary checks 58 (khtml::TypingCommand::forwardDeleteKeyPressed): 59 use SelectionController to extend selection, to get all the selection 60 logic incl. table selection and editable/noneditable boundary checks 61 1 62 2006-02-13 David Hyatt <hyatt@apple.com> 2 63 -
trunk/WebCore/dom/dom_position.cpp
r12725 r12789 482 482 } 483 483 484 bool hasRenderedChildrenWithHeight(RenderObject *renderer) 485 { 486 if (!renderer->firstChild()) 487 return false; 488 489 for (RenderObject *child = renderer->firstChild(); child; child = child->nextSibling()) 490 if (child->height()) 491 return true; 492 493 return false; 494 } 495 484 496 bool Position::inRenderedContent() const 485 497 { … … 497 509 return offset() == 0; 498 510 499 if (renderer->isText()) { 500 RenderText *textRenderer = static_cast<RenderText *>(renderer); 501 for (InlineTextBox *box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) { 502 if (offset() >= box->m_start && offset() <= box->m_start + box->m_len) 503 return true; 504 if (offset() < box->m_start) { 505 // The offset we're looking for is before this node 506 // this means the offset must be in content that is 507 // not rendered. Return false. 508 return false; 509 } 510 } 511 } else if (offset() >= renderer->caretMinOffset() && offset() <= renderer->caretMaxOffset()) { 512 // return true for replaced elements, for inline flows if they have a line box 513 // and for blocks if they are empty 514 if (renderer->isReplaced() || 515 (renderer->isInlineFlow() && static_cast<RenderFlow *>(renderer)->firstLineBox()) || 516 (renderer->isBlockFlow() && !renderer->firstChild() && renderer->height())) 517 return true; 518 } 511 if (renderer->isText()) 512 return inRenderedText(); 513 514 if (isTableElement(node()) || editingIgnoresContent(node())) 515 return offset() == 0 || offset() == maxDeepOffset(node()); 516 517 if (renderer->isBlockFlow() && !hasRenderedChildrenWithHeight(renderer) && 518 (renderer->height() || node()->hasTagName(bodyTag))) 519 return offset() == 0; 519 520 520 521 return false; -
trunk/WebCore/khtml/editing/SelectionController.cpp
r12765 r12789 284 284 switch (granularity) { 285 285 case CHARACTER: 286 pos = pos.next(); 286 if (isLastVisiblePositionBeforeTableElement(pos.deepEquivalent())) 287 pos = VisiblePosition(positionAfterFollowingTableElement(pos.deepEquivalent()), VP_DEFAULT_AFFINITY); 288 else 289 pos = pos.next(); 287 290 break; 288 291 case WORD: 289 pos = nextWordPosition(pos); 292 if (isLastVisiblePositionBeforeTableElement(pos.deepEquivalent())) 293 pos = VisiblePosition(positionAfterFollowingTableElement(pos.deepEquivalent()), VP_DEFAULT_AFFINITY); 294 else 295 pos = nextWordPosition(pos); 290 296 break; 291 297 case PARAGRAPH: … … 350 356 VisiblePosition pos(m_sel.extent(), m_sel.affinity()); 351 357 358 // Extending a selection backward by word or character from just after a table selects 359 // the table. This "makes sense" from the user perspective, esp. when deleting. 360 // It was done here instead of in VisiblePosition because we want VPs to iterate 361 // over everything. 352 362 switch (granularity) { 353 363 case CHARACTER: 354 // Extending a selection backward by character from just after a table selects355 // the table. This "makes sense" from the user perspective, esp. when deleting.356 // It was done here instead of in VisiblePosition because we want VPs to iterate357 // over everything.358 364 if (isFirstVisiblePositionAfterTableElement(pos.deepEquivalent())) 359 365 pos = VisiblePosition(positionBeforePrecedingTableElement(pos.deepEquivalent()), VP_DEFAULT_AFFINITY); … … 362 368 break; 363 369 case WORD: 364 pos = previousWordPosition(pos); 370 if (isFirstVisiblePositionAfterTableElement(pos.deepEquivalent())) 371 pos = VisiblePosition(positionBeforePrecedingTableElement(pos.deepEquivalent()), VP_DEFAULT_AFFINITY); 372 else 373 pos = previousWordPosition(pos); 365 374 break; 366 375 case PARAGRAPH: -
trunk/WebCore/khtml/editing/htmlediting.cpp
r12765 r12789 384 384 bool isFirstVisiblePositionAfterTableElement(const Position& pos) 385 385 { 386 VisiblePosition vPos = VisiblePosition(pos, DOWNSTREAM).previous(); 387 // FIXME: rangePos isn't being used to create DOM Ranges, so why does it need to be range compliant? 388 Position rangePos = rangeCompliantEquivalent(vPos.deepEquivalent().downstream()); 389 for (NodeImpl *n = rangePos.node(); n; n = n->parentNode()) { 390 // FIXME: can we not create a VP every time thru this loop? 391 VisiblePosition checkVP = VisiblePosition(n, maxRangeOffset(n), DOWNSTREAM); 392 if (checkVP != vPos) { 393 if (isTableElement(n) && checkVP.previous() == vPos) 394 return true; 395 return false; 396 } 397 if (n->rootEditableElement() == NULL) 398 return false; 399 if (isTableElement(n)) 400 return true; 401 } 402 403 return false; 386 return isTableElement(pos.upstream().node()); 404 387 } 405 388 … … 407 390 { 408 391 ASSERT(isFirstVisiblePositionAfterTableElement(pos)); 409 VisiblePosition vPos = VisiblePosition(pos, DOWNSTREAM).previous(); 410 // FIXME: rangePos isn't being used to create DOM Ranges, so why does it need to be range compliant? 411 Position rangePos = rangeCompliantEquivalent(vPos); 412 NodeImpl *outermostTableElement = NULL; 413 414 for (NodeImpl *n = rangePos.node(); n; n = n->parentNode()) { 415 // FIXME: can we not create a VP every time thru this loop? 416 VisiblePosition checkVP = VisiblePosition(n, maxRangeOffset(n), DOWNSTREAM); 417 if (checkVP != vPos) { 418 if (isTableElement(n) && checkVP.previous() == vPos) 419 outermostTableElement = n; 420 break; 421 } 422 if (n->rootEditableElement() == NULL) 423 break; 424 if (isTableElement(n)) 425 outermostTableElement = n; 426 } 427 428 ASSERT(outermostTableElement); 429 Position result = positionBeforeNode(outermostTableElement); 430 392 Position result = positionBeforeNode(pos.upstream().node()); 393 if (result.isNull() || !result.node()->rootEditableElement()) 394 return pos; 395 return result; 396 } 397 398 bool isLastVisiblePositionBeforeTableElement(const Position &pos) 399 { 400 return isTableElement(pos.downstream().node()); 401 } 402 403 Position positionAfterFollowingTableElement(const Position &pos) 404 { 405 ASSERT(isLastVisiblePositionBeforeTableElement(pos)); 406 Position result = positionAfterNode(pos.downstream().node()); 431 407 if (result.isNull() || !result.node()->rootEditableElement()) 432 408 return pos; … … 510 486 return pos; 511 487 512 return Position(node->parentNode(), node->nodeIndex());488 return positionBeforeNode(node); 513 489 } 514 490 -
trunk/WebCore/khtml/editing/htmlediting.h
r12725 r12789 89 89 bool isFirstVisiblePositionAfterTableElement(const Position&); 90 90 Position positionBeforePrecedingTableElement(const Position&); 91 bool isLastVisiblePositionBeforeTableElement(const Position&); 92 Position positionAfterFollowingTableElement(const Position&); 91 93 Position positionAvoidingSpecialElementBoundary(const Position&); 92 94 -
trunk/WebCore/khtml/editing/typing_command.cpp
r12178 r12789 28 28 #include "SelectionController.h" 29 29 30 #include "htmlediting.h" 30 31 #include "insert_text_command.h" 31 32 #include "insert_line_break_command.h" … … 67 68 if (isOpenForMoreTypingCommand(lastEditCommand)) { 68 69 static_cast<TypingCommand *>(lastEditCommand.get())->deleteKeyPressed(); 69 } 70 else { 71 Selection selection = frame->selection().selection(); 72 if (selection.isCaret() && VisiblePosition(selection.start(), selection.affinity()).previous().isNull()) { 73 // do nothing for a delete key at the start of an editable element. 74 } 75 else { 76 TypingCommand *typingCommand = new TypingCommand(document, DeleteKey); 77 typingCommand->setSmartDelete(smartDelete); 78 EditCommandPtr cmd(typingCommand); 79 cmd.apply(); 80 } 81 } 70 return; 71 } 72 73 TypingCommand *typingCommand = new TypingCommand(document, DeleteKey); 74 typingCommand->setSmartDelete(smartDelete); 75 EditCommandPtr cmd(typingCommand); 76 cmd.apply(); 82 77 } 83 78 … … 92 87 if (isOpenForMoreTypingCommand(lastEditCommand)) { 93 88 static_cast<TypingCommand *>(lastEditCommand.get())->forwardDeleteKeyPressed(); 94 } 95 else { 96 Selection selection = frame->selection().selection(); 97 if (selection.isCaret() && isEndOfDocument(VisiblePosition(selection.start(), selection.affinity()))) { 98 // do nothing for a delete key at the start of an editable element. 99 } 100 else { 101 TypingCommand *typingCommand = new TypingCommand(document, ForwardDeleteKey); 102 typingCommand->setSmartDelete(smartDelete); 103 EditCommandPtr cmd(typingCommand); 104 cmd.apply(); 105 } 106 } 89 return; 90 } 91 92 TypingCommand *typingCommand = new TypingCommand(document, ForwardDeleteKey); 93 typingCommand->setSmartDelete(smartDelete); 94 EditCommandPtr cmd(typingCommand); 95 cmd.apply(); 107 96 } 108 97 … … 117 106 if (isOpenForMoreTypingCommand(lastEditCommand)) { 118 107 static_cast<TypingCommand *>(lastEditCommand.get())->insertText(text, selectInsertedText); 119 }120 else {121 EditCommandPtr cmd(new TypingCommand(document, InsertText, text, selectInsertedText)); 122 cmd.apply();123 }108 return; 109 } 110 111 EditCommandPtr cmd(new TypingCommand(document, InsertText, text, selectInsertedText)); 112 cmd.apply(); 124 113 } 125 114 … … 134 123 if (isOpenForMoreTypingCommand(lastEditCommand)) { 135 124 static_cast<TypingCommand *>(lastEditCommand.get())->insertLineBreak(); 136 }137 else {138 EditCommandPtr cmd(new TypingCommand(document, InsertLineBreak)); 139 cmd.apply();140 }125 return; 126 } 127 128 EditCommandPtr cmd(new TypingCommand(document, InsertLineBreak)); 129 cmd.apply(); 141 130 } 142 131 … … 151 140 if (isOpenForMoreTypingCommand(lastEditCommand)) { 152 141 static_cast<TypingCommand *>(lastEditCommand.get())->insertParagraphSeparatorInQuotedContent(); 153 }154 else {155 EditCommandPtr cmd(new TypingCommand(document, InsertParagraphSeparatorInQuotedContent)); 156 cmd.apply();157 }142 return; 143 } 144 145 EditCommandPtr cmd(new TypingCommand(document, InsertParagraphSeparatorInQuotedContent)); 146 cmd.apply(); 158 147 } 159 148 … … 168 157 if (isOpenForMoreTypingCommand(lastEditCommand)) { 169 158 static_cast<TypingCommand *>(lastEditCommand.get())->insertParagraphSeparator(); 170 }171 else {172 EditCommandPtr cmd(new TypingCommand(document, InsertParagraphSeparator)); 173 cmd.apply();174 }159 return; 160 } 161 162 EditCommandPtr cmd(new TypingCommand(document, InsertParagraphSeparator)); 163 cmd.apply(); 175 164 } 176 165 … … 261 250 int newline; 262 251 while ((newline = text.find('\n', offset)) != -1) { 263 if (newline != offset) {252 if (newline != offset) 264 253 insertTextRunWithoutNewlines(text.substring(offset, newline - offset), false); 265 }266 254 insertParagraphSeparator(); 267 255 offset = newline + 1; 268 256 } 269 if (offset == 0) {257 if (offset == 0) 270 258 insertTextRunWithoutNewlines(text, selectInsertedText); 271 }else {259 else { 272 260 int length = text.length(); 273 261 if (length != offset) { … … 286 274 applyCommandToComposite(cmd); 287 275 impl->input(text, selectInsertedText); 288 } 289 else { 276 } else { 290 277 EditCommandPtr lastCommand = m_cmds.last(); 291 278 if (lastCommand.isInsertTextCommand()) { 292 279 InsertTextCommand *impl = static_cast<InsertTextCommand *>(lastCommand.get()); 293 280 impl->input(text, selectInsertedText); 294 } 295 else { 281 } else { 296 282 InsertTextCommand *impl = new InsertTextCommand(document()); 297 283 EditCommandPtr cmd(impl); … … 336 322 // Do nothing in the case that the caret is at the start of a 337 323 // root editable element or at the start of a document. 338 Position pos(endingSelection().start()); 339 Position start = VisiblePosition(pos, endingSelection().affinity()).previous().deepEquivalent(); 340 Position end = VisiblePosition(pos, endingSelection().affinity()).deepEquivalent(); 341 if (start.isNotNull() && end.isNotNull() && start.node()->rootEditableElement() == end.node()->rootEditableElement()) 342 selectionToDelete = Selection(start, end, SEL_DEFAULT_AFFINITY); 324 SelectionController sc = SelectionController(endingSelection().start(), endingSelection().end(), SEL_DEFAULT_AFFINITY); 325 sc.modify(SelectionController::EXTEND, SelectionController::BACKWARD, CHARACTER); 326 selectionToDelete = sc.selection(); 343 327 break; 344 328 } … … 367 351 // Do nothing in the case that the caret is at the start of a 368 352 // root editable element or at the start of a document. 369 Position pos(endingSelection().start()); 370 Position start = VisiblePosition(pos, endingSelection().affinity()).next().deepEquivalent(); 371 Position end = VisiblePosition(pos, endingSelection().affinity()).deepEquivalent(); 372 if (start.isNotNull() && end.isNotNull() && start.node()->rootEditableElement() == end.node()->rootEditableElement()) 373 selectionToDelete = Selection(start, end, SEL_DEFAULT_AFFINITY); 353 SelectionController sc = SelectionController(endingSelection().start(), endingSelection().end(), SEL_DEFAULT_AFFINITY); 354 sc.modify(SelectionController::EXTEND, SelectionController::FORWARD, CHARACTER); 355 selectionToDelete = sc.selection(); 374 356 break; 375 357 } -
trunk/WebCore/khtml/editing/visible_position.cpp
r12765 r12789 78 78 pos.node()->getDocument()->updateLayoutIgnorePendingStylesheets(); 79 79 Position deepPos = deepEquivalent(pos); 80 if ( isCandidate(deepPos)) {80 if (deepPos.inRenderedContent()) { 81 81 m_deepPosition = deepPos; 82 82 Position previous = previousVisiblePosition(deepPos); … … 150 150 Position test = deepEquivalent(pos); 151 151 Position downstreamTest = test.downstream(); 152 bool acceptAnyVisiblePosition = ! isCandidate(test);152 bool acceptAnyVisiblePosition = !test.inRenderedContent(); 153 153 154 154 Position current = test; 155 155 while (!current.atStart()) { 156 156 current = current.previous(UsingComposedCharacters); 157 if ( isCandidate(current) && (acceptAnyVisiblePosition || (downstreamTest != current.downstream()))) {157 if (current.inRenderedContent() && (acceptAnyVisiblePosition || (downstreamTest != current.downstream()))) { 158 158 return current; 159 159 } … … 169 169 170 170 Position test = deepEquivalent(pos); 171 bool acceptAnyVisiblePosition = ! isCandidate(test);171 bool acceptAnyVisiblePosition = !test.inRenderedContent(); 172 172 173 173 Position current = test; … … 175 175 while (!current.atEnd()) { 176 176 current = current.next(UsingComposedCharacters); 177 if ( isCandidate(current) && (acceptAnyVisiblePosition || (downstreamTest != current.downstream()))) {177 if (current.inRenderedContent() && (acceptAnyVisiblePosition || (downstreamTest != current.downstream()))) { 178 178 return current; 179 179 } … … 183 183 } 184 184 185 bool hasRenderedChildrenWithHeight(RenderObject *renderer)186 {187 if (!renderer->firstChild())188 return false;189 190 for (RenderObject *child = renderer->firstChild(); child; child = child->nextSibling())191 if (child->height())192 return true;193 194 return false;195 }196 197 bool VisiblePosition::isCandidate(const Position &pos)198 {199 if (pos.isNull())200 return false;201 202 RenderObject *renderer = pos.node()->renderer();203 if (!renderer)204 return false;205 206 if (renderer->style()->visibility() != VISIBLE)207 return false;208 209 if (isTableElement(pos.node()) || editingIgnoresContent(pos.node()))210 return pos.offset() == 0 || pos.offset() == maxDeepOffset(pos.node());211 212 if (renderer->isBR())213 return pos.offset() == 0;214 215 // True if at a rendered offset inside a text node216 if (renderer->isText()) {217 RenderText *textRenderer = static_cast<RenderText *>(renderer);218 for (InlineTextBox *box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) {219 if (pos.offset() >= box->m_start && pos.offset() <= box->m_start + box->m_len) {220 return true;221 }222 }223 }224 225 if (renderer->isBlockFlow() && !hasRenderedChildrenWithHeight(renderer) &&226 (renderer->height() || pos.node()->hasTagName(bodyTag)))227 return pos.offset() == 0;228 229 return false;230 }231 232 185 Position VisiblePosition::deepEquivalent(const Position &pos) 233 186 { … … 238 191 return Position(); 239 192 240 if ( isCandidate(pos) || isAtomicNode(node))193 if (pos.inRenderedContent() || isAtomicNode(node)) 241 194 return pos; 242 195 … … 247 200 break; 248 201 node = child; 249 } while (! isCandidate(Position(node, maxDeepOffset(node))) && !isAtomicNode(node));202 } while (!(Position(node, maxDeepOffset(node)).inRenderedContent()) && !isAtomicNode(node)); 250 203 return Position(node, maxDeepOffset(node)); 251 204 } … … 253 206 node = node->childNode(offset); 254 207 ASSERT(node); 255 while (! isCandidate(Position(node, 0)) && !isAtomicNode(node)) {208 while (!(Position(node, 0).inRenderedContent()) && !isAtomicNode(node)) { 256 209 NodeImpl *child = node->firstChild(); 257 210 if (!child) -
trunk/WebCore/khtml/editing/visible_position.h
r12715 r12789 106 106 static Position previousVisiblePosition(const Position &); 107 107 static Position nextVisiblePosition(const Position &); 108 109 static bool isCandidate(const Position &);110 108 111 109 Position m_deepPosition;
Note: See TracChangeset
for help on using the changeset viewer.