Changeset 21861 in webkit
- Timestamp:
- May 29, 2007, 12:39:14 PM (18 years ago)
- Location:
- trunk
- Files:
-
- 2 added
- 14 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/LayoutTests/ChangeLog
r21847 r21861 1 2007-05-29 Darin Adler <darin@apple.com> 2 3 Reviewed by Maciej. 4 5 - test for http://bugs.webkit.org/show_bug.cgi?id=13602 6 Amazon product pages keep repainting over and over again 7 8 * fast/dom/HTMLElement/set-inner-outer-optimization-expected.txt: Added. 9 * fast/dom/HTMLElement/set-inner-outer-optimization.html: Added. 10 11 * editing/execCommand/copy-without-selection.html: Added missing preventDefault calls 12 to prevent this from being a double-paste test. 13 14 * fast/css/first-letter-detach-expected.checksum: Updated. 15 * fast/css/first-letter-detach-expected.png: Updated. 16 * fast/css/first-letter-detach-expected.txt: Updated. 17 * fast/css/first-letter-detach.html: Updated to test three different ways of setting the 18 text of the first-letter element; setInnerHTML and two other ways. 19 20 * fast/events/updateLayoutForHitTest-expected.txt: Updated result that changed slightly 21 due to setInnerHTML improvement. 22 * fast/forms/textarea-setinnerhtml-expected.txt: Ditto. 23 1 24 2007-05-28 Mitz Pettel <mitz@webkit.org> 2 25 -
trunk/LayoutTests/editing/execCommand/copy-without-selection.html
r19109 r21861 6 6 { 7 7 event.clipboardData.setData('text/plain', "SUCCESS"); 8 event.preventDefault(); 8 9 } 9 10 … … 12 13 var clip = event.clipboardData.getData('text/plain'); 13 14 document.getElementById('result').innerHTML = clip; 15 event.preventDefault(); 14 16 } 15 17 -
trunk/LayoutTests/fast/css/first-letter-detach-expected.checksum
r13463 r21861 1 8a18d46db2930f0b446f96f59f3747c2 1 5997df311efaf8e91463da7355bba208 -
trunk/LayoutTests/fast/css/first-letter-detach-expected.txt
r14684 r21861 17 17 text run at (189,18) width 4: "." 18 18 RenderBlock {P} at (0,52) size 784x18 19 RenderText {#text} at (0,0) size 171x1820 text run at (0,0) width 171: "The next line shouldread \x{201C}"19 RenderText {#text} at (0,0) size 231x18 20 text run at (0,0) width 231: "The next three lines should all read \x{201C}" 21 21 RenderInline {SPAN} at (0,0) size 9x18 [color=#0000FF] 22 RenderText {#text} at ( 171,0) size 9x1823 text run at ( 171,0) width 9: "P"24 RenderText {#text} at ( 180,0) size 209x1825 text run at ( 180,0) width 209: "ASS\x{201D}, with nothing before the P."22 RenderText {#text} at (231,0) size 9x18 23 text run at (231,0) width 9: "P" 24 RenderText {#text} at (240,0) size 209x18 25 text run at (240,0) width 209: "ASS\x{201D}, with nothing before the P." 26 26 RenderBlock {HR} at (0,86) size 784x2 [border: (1px inset #000000)] 27 27 RenderBlock {P} at (0,104) size 784x18 … … 31 31 RenderText {#text} at (9,0) size 30x18 32 32 text run at (9,0) width 30: "ASS" 33 RenderBlock {P} at (0,138) size 784x18 34 RenderInline (generated) at (0,0) size 9x18 [color=#0000FF] 35 RenderText {#text} at (0,0) size 9x18 36 text run at (0,0) width 9: "P" 37 RenderText {#text} at (9,0) size 30x18 38 text run at (9,0) width 30: "ASS" 39 RenderBlock {P} at (0,172) size 784x18 40 RenderInline (generated) at (0,0) size 9x18 [color=#0000FF] 41 RenderText {#text} at (0,0) size 9x18 42 text run at (0,0) width 9: "P" 43 RenderText {#text} at (9,0) size 30x18 44 text run at (9,0) width 30: "ASS" -
trunk/LayoutTests/fast/css/first-letter-detach.html
r13356 r21861 4 4 <title></title> 5 5 <style type="text/css"> 6 #target:first-letter { color: blue; } 6 #targeta:first-letter { color: blue; } 7 #targetb:first-letter { color: blue; } 8 #targetc:first-letter { color: blue; } 7 9 </style> 8 10 … … 11 13 { 12 14 document.body.offsetTop; 13 document.getElementById("target").innerHTML = "PASS"; 15 document.getElementById("targeta").innerHTML = "PASS"; 16 document.getElementById("targetb").firstChild.data = "PASS"; 17 document.getElementById("targetc").replaceChild(document.createTextNode("PASS"), document.getElementById("targetc").firstChild); 14 18 } 15 19 </script> … … 22 26 </p> 23 27 <p> 24 The next line shouldread “<span style="color: blue;">P</span>ASS”, with nothing before the P.28 The next three lines should all read “<span style="color: blue;">P</span>ASS”, with nothing before the P. 25 29 </p> 26 30 <hr> 27 <p id="target">didn’t run</p> 31 <p id="targeta">didn’t run</p> 32 <p id="targetb">didn’t run</p> 33 <p id="targetc">didn’t run</p> 28 34 </body> 29 35 </html> -
trunk/LayoutTests/fast/events/updateLayoutForHitTest-expected.txt
r19343 r21861 15 15 text run at (14,5) width 48: " Project" 16 16 RenderText {#text} at (0,0) size 0x0 17 selection start: position 0 of child 0 {#text} of child 1 {SPAN} of child 3 {DIV} of child 1 {BODY} of child 0 {HTML} of document 18 selection end: position 0 of child 1 {#text} of child 3 {DIV} of child 3 {DIV} of child 1 {BODY} of child 0 {HTML} of document -
trunk/WebCore/ChangeLog
r21860 r21861 1 2007-05-29 Darin Adler <darin@apple.com> 2 3 Reviewed by Maciej. 4 5 - fix http://bugs.webkit.org/show_bug.cgi?id=13602 6 Amazon product pages keep repainting over and over again 7 8 - fix first-letter when the text of the affected text node is changed 9 10 Optimize setInnerHTML, setOuterHTML, and setInnerText so they don't change the DOM at all 11 if they don't need to. 12 13 Test: fast/dom/HTMLElement/set-inner-outer-optimization.html 14 Test: fast/css/first-letter-detach.html 15 16 * html/HTMLElement.cpp: 17 (WebCore::equal): Added. Helper function that compares two Text nodes or two NamedAttrMap 18 attribute maps. 19 (WebCore::shallowEqual): Added. Helper function that compares two Element nodes or two 20 arbitrary nodes. 21 (WebCore::childrenAreEqual): Added. Helper functions that compare children of nodes. 22 (WebCore::hasOneChild): Added. Helper function. 23 (WebCore::hasOneTextChild): Added. Helper function. 24 (WebCore::replaceChildrenWithFragment): Added. Helper function used by setInnerHTML and 25 setInnerText. Optimizes the cases where all the nodes are the same, where both the current 26 and the new content are single text nodes, and where the current content is a single node 27 that can be replaced with replaceChild. 28 (WebCore::replaceChildrenWithText): Added. Helper function used by setInnerText. Optimizes 29 the case where the current content is a single text node or a single node that can be 30 replaced with replaceChild. 31 (WebCore::HTMLElement::setInnerHTML): Changed to call replaceChildrenWithFragment. 32 (WebCore::HTMLElement::setOuterHTML): Added special case to optimize when the new content 33 exactly matches the current node. 34 (WebCore::HTMLElement::setInnerText): Changed to call replaceChildrenWithText in a few 35 cases instead of doing removeChildren/appendChild. Changed code that was using 36 DeprecatedString to instead use String. Changed general case to use a document fragment 37 and replaceChildrenWithFragment. 38 39 * dom/CharacterData.cpp: (WebCore::CharacterData::dispatchModifiedEvent): 40 Fixed bug where we would not dispatch the DOMSubtreeModified event unless someone 41 was registered for the DOMCharacterDataModified event. Caused trouble in the test. 42 43 * rendering/RenderBlock.cpp: (WebCore::RenderBlock::updateFirstLetter): Set first-letter 44 after the setStyle call so calls to setTextInternal inside setStyle don't clear it. 45 46 * rendering/RenderText.h: Made setTextInternal virtual so that RenderTextFragment can do 47 appropriate work when the text changes. 48 49 * rendering/RenderTextFragment.h: Added an override of setTextInternal. Removed the 50 firstLetter parameter to the constructor and made it a separate setter. Also changed 51 m_generatedContentStr to m_contentString to match the getter function. 52 * rendering/RenderTextFragment.cpp: 53 (WebCore::RenderTextFragment::RenderTextFragment): Removed firstLetter parameter. 54 (WebCore::RenderTextFragment::setTextInternal): When the text changes, destroy the 55 first-letter node and reset the fragment values so that RenderBlock::updateFirstLetter, 56 which will run during layout, will create a new first-letter child. Otherwise we end up 57 with the first letter of the old text. 58 1 59 2007-05-29 Sam Weinig <sam@webkit.org> 2 60 -
trunk/WebCore/dom/CharacterData.cpp
r21287 r21861 230 230 if (parentNode()) 231 231 parentNode()->childrenChanged(); 232 if (!document()->hasListenerType(Document::DOMCHARACTERDATAMODIFIED_LISTENER)) 233 return; 234 235 StringImpl *newValue = str->copy(); 236 newValue->ref(); 237 ExceptionCode ec = 0; 238 dispatchEvent(new MutationEvent(DOMCharacterDataModifiedEvent, 239 true,false,0,prevValue,newValue,String(),0),ec); 240 newValue->deref(); 232 if (document()->hasListenerType(Document::DOMCHARACTERDATAMODIFIED_LISTENER)) { 233 StringImpl *newValue = str->copy(); 234 newValue->ref(); 235 ExceptionCode ec = 0; 236 dispatchEvent(new MutationEvent(DOMCharacterDataModifiedEvent, 237 true,false,0,prevValue,newValue,String(),0),ec); 238 newValue->deref(); 239 } 241 240 dispatchSubtreeModifiedEvent(); 242 241 } -
trunk/WebCore/html/HTMLElement.cpp
r21856 r21861 281 281 } 282 282 283 void HTMLElement::setInnerHTML(const String &html, ExceptionCode& ec) 283 static inline bool equal(NamedAttrMap* a, NamedAttrMap* b) 284 { 285 // empty maps; empty and null maps are equivalent 286 if (!a) { 287 if (!b) 288 return true; 289 return !b->length(); 290 } 291 if (!b) 292 return !a->length(); 293 294 unsigned len = a->length(); 295 if (b->length() != len) 296 return false; 297 298 for (unsigned i = 0; i < len; ++i) { 299 Attribute* aa = a->attributeItem(i); 300 Attribute* ba = b->attributeItem(i); 301 if (aa->name() != ba->name()) 302 return false; 303 if (aa->value() != ba->value()) 304 return false; 305 } 306 307 return true; 308 } 309 310 static inline bool shallowEqual(Element* a, Element* b) 311 { 312 return a->tagQName() == b->tagQName() && equal(a->attributes(false), b->attributes(false)); 313 } 314 315 static bool shallowEqual(Node* a, Node* b) 316 { 317 Node::NodeType ta = a->nodeType(); 318 Node::NodeType tb = b->nodeType(); 319 if (ta != tb) 320 return false; 321 322 switch (ta) { 323 case Node::ATTRIBUTE_NODE: 324 case Node::DOCUMENT_FRAGMENT_NODE: 325 case Node::DOCUMENT_NODE: 326 case Node::DOCUMENT_TYPE_NODE: 327 case Node::ENTITY_NODE: 328 case Node::ENTITY_REFERENCE_NODE: 329 case Node::NOTATION_NODE: 330 case Node::PROCESSING_INSTRUCTION_NODE: 331 case Node::XPATH_NAMESPACE_NODE: 332 // Don't bother comparing these node types for now; they don't typically occur. 333 // Since these functions are used only for optimization, it's OK to have a false negative. 334 // Also, some of these node types can't occur the subtree of an HTML element, 335 // and we won't ever call this function for those. 336 return false; 337 case Node::CDATA_SECTION_NODE: 338 case Node::COMMENT_NODE: 339 case Node::TEXT_NODE: 340 return equal(static_cast<CharacterData*>(a)->string(), static_cast<CharacterData*>(b)->string()); 341 case Node::ELEMENT_NODE: 342 return shallowEqual(static_cast<Element*>(a), static_cast<Element*>(b)); 343 } 344 345 ASSERT_NOT_REACHED(); 346 return false; 347 } 348 349 static bool childrenAreEqual(ContainerNode* containerA, ContainerNode* containerB) 350 { 351 ASSERT(containerA); 352 ASSERT(containerB); 353 Node* a = containerA->firstChild(); 354 Node* b = containerB->firstChild(); 355 while (a && b) { 356 if (!shallowEqual(a, b)) 357 return false; 358 a = a->traverseNextNode(containerA); 359 b = b->traverseNextNode(containerB); 360 } 361 return !a && !b; 362 } 363 364 static bool childrenAreEqual(ContainerNode* containerA, ContainerNode* containerB, Node* startNodeA, Node* stopNodeA) 365 { 366 ASSERT(containerA); 367 ASSERT(containerB); 368 ASSERT(startNodeA->parentNode() == containerA); 369 ASSERT(!stopNodeA || stopNodeA->parentNode() == containerA); 370 Node* a = startNodeA; 371 Node* b = containerB->firstChild(); 372 while (a != stopNodeA && b) { 373 if (!shallowEqual(a, b)) 374 return false; 375 a = a->traverseNextNode(containerA); 376 b = b->traverseNextNode(containerB); 377 } 378 return a == stopNodeA && !b; 379 } 380 381 static inline bool hasOneChild(ContainerNode* node) 382 { 383 Node* firstChild = node->firstChild(); 384 return firstChild && !firstChild->nextSibling(); 385 } 386 387 static inline bool hasOneTextChild(ContainerNode* node) 388 { 389 return hasOneChild(node) && node->firstChild()->isTextNode(); 390 } 391 392 static void replaceChildrenWithFragment(HTMLElement* element, PassRefPtr<DocumentFragment> fragment, ExceptionCode& ec) 393 { 394 if (!fragment->firstChild()) { 395 element->removeChildren(); 396 return; 397 } 398 399 if (childrenAreEqual(element, fragment.get())) 400 return; 401 402 if (hasOneTextChild(element) && hasOneTextChild(fragment.get())) { 403 static_cast<Text*>(element->firstChild())->setData(static_cast<Text*>(fragment->firstChild())->string(), ec); 404 return; 405 } 406 407 if (hasOneChild(element)) { 408 element->replaceChild(fragment, element->firstChild(), ec); 409 return; 410 } 411 412 element->removeChildren(); 413 element->appendChild(fragment, ec); 414 } 415 416 static void replaceChildrenWithText(HTMLElement* element, const String& text, ExceptionCode& ec) 417 { 418 if (hasOneTextChild(element)) { 419 Text* textChild = static_cast<Text*>(element->firstChild()); 420 if (equal(textChild->string(), text.impl())) 421 return; 422 textChild->setData(text, ec); 423 return; 424 } 425 426 RefPtr<Text> textNode = new Text(element->document(), text); 427 428 if (hasOneChild(element)) { 429 element->replaceChild(textNode.release(), element->firstChild(), ec); 430 return; 431 } 432 433 element->removeChildren(); 434 element->appendChild(textNode.release(), ec); 435 } 436 437 void HTMLElement::setInnerHTML(const String& html, ExceptionCode& ec) 284 438 { 285 439 RefPtr<DocumentFragment> fragment = createContextualFragment(html); … … 289 443 } 290 444 291 // FIXME: Add special case for when we had one text child and we just want to set its text? 292 // FIXME: Add special case for cases where we can use replaceChild? 293 294 removeChildren(); 295 appendChild(fragment.release(), ec); 296 } 297 298 void HTMLElement::setOuterHTML(const String &html, ExceptionCode& ec) 445 replaceChildrenWithFragment(this, fragment.release(), ec); 446 } 447 448 void HTMLElement::setOuterHTML(const String& html, ExceptionCode& ec) 299 449 { 300 450 Node* p = parent(); … … 311 461 } 312 462 313 // FIXME: Add special case for when we had one text child and we just want to set its text?314 463 // FIXME: Why doesn't this have code to merge neighboring text nodes the way setOuterText does? 464 465 // Check to see if content is identical. 466 if (childrenAreEqual(parent, fragment.get(), this, nextSibling())) 467 return; 468 315 469 parent->replaceChild(fragment.release(), this, ec); 316 470 } … … 332 486 333 487 // FIXME: This doesn't take whitespace collapsing into account at all. 334 // FIXME: Add special case for when we had one text child and we just want to set its text?335 // FIXME: Add special case for cases where we can use replaceChild?336 337 removeChildren();338 488 339 489 if (!text.contains('\n') && !text.contains('\r')) { 340 if (text.isEmpty()) 490 if (text.isEmpty()) { 491 removeChildren(); 341 492 return; 342 appendChild(new Text(document(), text), ec); 493 } 494 replaceChildrenWithText(this, text, ec); 343 495 return; 344 496 } … … 350 502 if (r && r->style()->preserveNewline()) { 351 503 if (!text.contains('\r')) { 352 appendChild(new Text(document(), text), ec);504 replaceChildrenWithText(this, text, ec); 353 505 return; 354 506 } 355 // FIXME: Stick with String once it has a replace that can do this. 356 DeprecatedString textWithConsistentLineBreaks = text.deprecatedString(); 507 String textWithConsistentLineBreaks = text; 357 508 textWithConsistentLineBreaks.replace("\r\n", "\n"); 358 509 textWithConsistentLineBreaks.replace('\r', '\n'); 359 appendChild(new Text(document(), textWithConsistentLineBreaks), ec);510 replaceChildrenWithText(this, textWithConsistentLineBreaks, ec); 360 511 return; 361 512 } … … 363 514 // Add text nodes and <br> elements. 364 515 ec = 0; 516 RefPtr<DocumentFragment> fragment = new DocumentFragment(document()); 365 517 int lineStart = 0; 366 518 UChar prev = 0; … … 370 522 if (c == '\n' || c == '\r') { 371 523 if (i > lineStart) { 372 appendChild(new Text(document(), text.substring(lineStart, i - lineStart)), ec);524 fragment->appendChild(new Text(document(), text.substring(lineStart, i - lineStart)), ec); 373 525 if (ec) 374 526 return; 375 527 } 376 528 if (!(c == '\n' && i != 0 && prev == '\r')) { 377 appendChild(new HTMLBRElement(document()), ec);529 fragment->appendChild(new HTMLBRElement(document()), ec); 378 530 if (ec) 379 531 return; … … 384 536 } 385 537 if (length > lineStart) 386 appendChild(new Text(document(), text.substring(lineStart, length - lineStart)), ec); 538 fragment->appendChild(new Text(document(), text.substring(lineStart, length - lineStart)), ec); 539 replaceChildrenWithFragment(this, fragment.release(), ec); 387 540 } 388 541 -
trunk/WebCore/rendering/RenderBlock.cpp
r21747 r21861 4136 4136 // NOTE: this might empty 4137 4137 RenderTextFragment* remainingText = 4138 new (renderArena()) RenderTextFragment(textObj->node(), oldText.get(), length, oldText->length() - length , firstLetter);4138 new (renderArena()) RenderTextFragment(textObj->node(), oldText.get(), length, oldText->length() - length); 4139 4139 remainingText->setStyle(textObj->style()); 4140 remainingText->setFirstLetter(firstLetter); 4140 4141 if (remainingText->element()) 4141 4142 remainingText->element()->setRenderer(remainingText); -
trunk/WebCore/rendering/RenderText.h
r21387 r21861 128 128 129 129 protected: 130 v oid setTextInternal(PassRefPtr<StringImpl>);130 virtual void setTextInternal(PassRefPtr<StringImpl>); 131 131 virtual void calcPrefWidths(int leadWidth); 132 132 -
trunk/WebCore/rendering/RenderTextFragment.cpp
r19027 r21861 1 /** 2 * This file is part of the DOM implementation for KDE. 3 * 1 /* 4 2 * (C) 1999 Lars Knoll (knoll@kde.org) 5 3 * (C) 2000 Dirk Mueller (mueller@kde.org) 6 * Copyright (C) 2004, 2005, 2006 Apple Computer, Inc.4 * Copyright (C) 2004, 2005, 2006, 2007 Apple Inc. All rights reserved. 7 5 * 8 6 * This library is free software; you can redistribute it and/or … … 30 28 namespace WebCore { 31 29 32 RenderTextFragment::RenderTextFragment(Node* node, StringImpl* str, int startOffset, int length , RenderObject* firstLetter)30 RenderTextFragment::RenderTextFragment(Node* node, StringImpl* str, int startOffset, int length) 33 31 : RenderText(node, str ? str->substring(startOffset, length) : 0) 34 32 , m_start(startOffset) 35 33 , m_end(length) 36 , m_firstLetter( firstLetter)34 , m_firstLetter(0) 37 35 { 38 36 } … … 42 40 , m_start(0) 43 41 , m_end(str ? str->length() : 0) 44 , m_ generatedContentStr(str)42 , m_contentString(str) 45 43 , m_firstLetter(0) 46 44 { … … 58 56 void RenderTextFragment::destroy() 59 57 { 60 if ( firstLetter())61 firstLetter()->destroy();58 if (m_firstLetter) 59 m_firstLetter->destroy(); 62 60 RenderText::destroy(); 63 61 } 64 62 63 void RenderTextFragment::setTextInternal(PassRefPtr<StringImpl> text) 64 { 65 RenderText::setTextInternal(text); 66 if (m_firstLetter) { 67 ASSERT(!m_contentString); 68 m_firstLetter->destroy(); 69 m_firstLetter = 0; 70 m_start = 0; 71 m_end = textLength(); 72 } 73 } 74 65 75 } // namespace WebCore -
trunk/WebCore/rendering/RenderTextFragment.h
r19027 r21861 1 1 /* 2 * This file is part of the DOM implementation for KDE.3 *4 2 * (C) 1999 Lars Knoll (knoll@kde.org) 5 3 * (C) 2000 Dirk Mueller (mueller@kde.org) 6 * Copyright (C) 2004, 2005, 2006 Apple Computer, Inc.4 * Copyright (C) 2004, 2005, 2006, 2007 Apple Inc. All rights reserved. 7 5 * 8 6 * This library is free software; you can redistribute it and/or … … 36 34 class RenderTextFragment : public RenderText { 37 35 public: 38 RenderTextFragment(Node*, StringImpl*, int startOffset, int length , RenderObject* firstLetter = 0);36 RenderTextFragment(Node*, StringImpl*, int startOffset, int length); 39 37 RenderTextFragment(Node*, StringImpl*); 40 38 … … 45 43 unsigned start() const { return m_start; } 46 44 unsigned end() const { return m_end; } 45 47 46 RenderObject* firstLetter() const { return m_firstLetter; } 47 void setFirstLetter(RenderObject* firstLetter) { m_firstLetter = firstLetter; } 48 48 49 StringImpl* contentString() const { return m_ generatedContentStr.get(); }49 StringImpl* contentString() const { return m_contentString.get(); } 50 50 virtual PassRefPtr<StringImpl> originalText() const; 51 51 52 52 private: 53 virtual void setTextInternal(PassRefPtr<StringImpl>); 54 53 55 unsigned m_start; 54 56 unsigned m_end; 55 RefPtr<StringImpl> m_ generatedContentStr;57 RefPtr<StringImpl> m_contentString; 56 58 RenderObject* m_firstLetter; 57 59 };
Note:
See TracChangeset
for help on using the changeset viewer.