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

Side by Side Diff: Source/core/rendering/RenderBlock.cpp

Issue 14113040: Update the first letter when the first line is changed by adding a new text at its start. (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@first-letter-rendering-issue
Patch Set: Created 7 years, 8 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
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org) 2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3 * (C) 1999 Antti Koivisto (koivisto@kde.org) 3 * (C) 1999 Antti Koivisto (koivisto@kde.org)
4 * (C) 2007 David Smith (catfish.man@gmail.com) 4 * (C) 2007 David Smith (catfish.man@gmail.com)
5 * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights reserved. 5 * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights reserved.
6 * Copyright (C) Research In Motion Limited 2010. All rights reserved. 6 * Copyright (C) Research In Motion Limited 2010. All rights reserved.
7 * 7 *
8 * This library is free software; you can redistribute it and/or 8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public 9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either 10 * License as published by the Free Software Foundation; either
(...skipping 13 matching lines...) Expand all
24 #include "config.h" 24 #include "config.h"
25 #include "core/rendering/RenderBlock.h" 25 #include "core/rendering/RenderBlock.h"
26 26
27 #include "HTMLFormElement.h" 27 #include "HTMLFormElement.h"
28 #include "HTMLNames.h" 28 #include "HTMLNames.h"
29 #include "core/accessibility/AXObjectCache.h" 29 #include "core/accessibility/AXObjectCache.h"
30 #include "core/dom/Document.h" 30 #include "core/dom/Document.h"
31 #include "core/dom/Element.h" 31 #include "core/dom/Element.h"
32 #include "core/dom/OverflowEvent.h" 32 #include "core/dom/OverflowEvent.h"
33 #include "core/dom/ShadowRoot.h" 33 #include "core/dom/ShadowRoot.h"
34 #include "core/dom/Text.h"
34 #include "core/dom/WebCoreMemoryInstrumentation.h" 35 #include "core/dom/WebCoreMemoryInstrumentation.h"
35 #include "core/editing/Editor.h" 36 #include "core/editing/Editor.h"
36 #include "core/editing/FrameSelection.h" 37 #include "core/editing/FrameSelection.h"
37 #include "core/page/Frame.h" 38 #include "core/page/Frame.h"
38 #include "core/page/FrameView.h" 39 #include "core/page/FrameView.h"
39 #include "core/page/Page.h" 40 #include "core/page/Page.h"
40 #include "core/page/Settings.h" 41 #include "core/page/Settings.h"
41 #include "core/platform/PODFreeListArena.h" 42 #include "core/platform/PODFreeListArena.h"
42 #include "core/platform/graphics/FloatQuad.h" 43 #include "core/platform/graphics/FloatQuad.h"
43 #include "core/platform/graphics/GraphicsContext.h" 44 #include "core/platform/graphics/GraphicsContext.h"
(...skipping 6569 matching lines...) Expand 10 before | Expand all | Expand 10 after
6613 firstLetterContainer->addChild(firstLetter, nextSibling); 6614 firstLetterContainer->addChild(firstLetter, nextSibling);
6614 } else 6615 } else
6615 firstLetter->setStyle(pseudoStyle); 6616 firstLetter->setStyle(pseudoStyle);
6616 6617
6617 for (RenderObject* genChild = firstLetter->firstChild(); genChild; genChild = genChild->nextSibling()) { 6618 for (RenderObject* genChild = firstLetter->firstChild(); genChild; genChild = genChild->nextSibling()) {
6618 if (genChild->isText()) 6619 if (genChild->isText())
6619 genChild->setStyle(pseudoStyle); 6620 genChild->setStyle(pseudoStyle);
6620 } 6621 }
6621 } 6622 }
6622 6623
6624 static inline unsigned whiteSpaceLength(PassRefPtr<StringImpl> oldText)
esprehn 2013/05/06 20:43:58 Just take a String not a RefPtr<StringImpl>
6625 {
6626 unsigned length = 0;
6627 // Account for leading spaces and punctuation.
6628 while (length < oldText->length() && shouldSkipForFirstLetter((*oldText)[len gth]))
6629 length++;
6630
6631 // Account for first letter.
6632 length++;
6633
6634 // Keep looking for whitespace and allowed punctuation, but avoid
6635 // accumulating just whitespace into the :first-letter.
6636 for (unsigned scanLength = length; scanLength < oldText->length(); ++scanLen gth) {
6637 UChar c = (*oldText)[scanLength];
6638
6639 if (!shouldSkipForFirstLetter(c))
6640 break;
6641
6642 if (isPunctuationForFirstLetter(c))
6643 length = scanLength + 1;
6644 }
6645
6646 return length;
6647 }
6648
6623 void RenderBlock::createFirstLetterRenderer(RenderObject* firstLetterBlock, Rend erObject* currentChild) 6649 void RenderBlock::createFirstLetterRenderer(RenderObject* firstLetterBlock, Rend erObject* currentChild)
6624 { 6650 {
6625 RenderObject* firstLetterContainer = currentChild->parent(); 6651 RenderObject* firstLetterContainer = currentChild->parent();
6626 RenderStyle* pseudoStyle = styleForFirstLetter(firstLetterBlock, firstLetter Container); 6652 RenderStyle* pseudoStyle = styleForFirstLetter(firstLetterBlock, firstLetter Container);
6627 RenderObject* firstLetter = 0; 6653 RenderObject* firstLetter = 0;
6628 if (pseudoStyle->display() == INLINE) 6654 if (pseudoStyle->display() == INLINE)
6629 firstLetter = RenderInline::createAnonymous(document()); 6655 firstLetter = RenderInline::createAnonymous(document());
6630 else 6656 else
6631 firstLetter = RenderBlock::createAnonymous(document()); 6657 firstLetter = RenderBlock::createAnonymous(document());
6632 firstLetter->setStyle(pseudoStyle); 6658 firstLetter->setStyle(pseudoStyle);
6633 firstLetterContainer->addChild(firstLetter, currentChild); 6659 firstLetterContainer->addChild(firstLetter, currentChild);
6634 6660
6635 RenderText* textObj = toRenderText(currentChild); 6661 RenderText* textObj = toRenderText(currentChild);
6636 6662
6637 // The original string is going to be either a generated content string or a DOM node's 6663 // The original string is going to be either a generated content string or a DOM node's
6638 // string. We want the original string before it got transformed in case fi rst-letter has 6664 // string. We want the original string before it got transformed in case fi rst-letter has
6639 // no text-transform or a different text-transform applied to it. 6665 // no text-transform or a different text-transform applied to it.
6640 RefPtr<StringImpl> oldText = textObj->originalText(); 6666 RefPtr<StringImpl> oldText = textObj->originalText();
esprehn 2013/05/06 20:43:58 Change to String
6641 ASSERT(oldText); 6667 ASSERT(oldText);
6642 6668
6643 if (oldText && oldText->length() > 0) { 6669 if (oldText && oldText->length() > 0) {
6644 unsigned length = 0; 6670 unsigned length = 0;
6671 length = whiteSpaceLength(oldText);
6645 6672
6646 // Account for leading spaces and punctuation.
6647 while (length < oldText->length() && shouldSkipForFirstLetter((*oldText) [length]))
6648 length++;
6649
6650 // Account for first letter.
6651 length++;
6652
6653 // Keep looking for whitespace and allowed punctuation, but avoid
6654 // accumulating just whitespace into the :first-letter.
6655 for (unsigned scanLength = length; scanLength < oldText->length(); ++sca nLength) {
6656 UChar c = (*oldText)[scanLength];
6657
6658 if (!shouldSkipForFirstLetter(c))
6659 break;
6660
6661 if (isPunctuationForFirstLetter(c))
6662 length = scanLength + 1;
6663 }
6664
6665 // Construct a text fragment for the text after the first letter. 6673 // Construct a text fragment for the text after the first letter.
6666 // This text fragment might be empty. 6674 // This text fragment might be empty.
6667 RenderTextFragment* remainingText = 6675 RenderTextFragment* remainingText =
6668 new (renderArena()) RenderTextFragment(textObj->node() ? textObj->no de() : textObj->document(), oldText.get(), length, oldText->length() - length); 6676 new (renderArena()) RenderTextFragment(textObj->node() ? textObj->no de() : textObj->document(), oldText.get(), length, oldText->length() - length);
6669 remainingText->setStyle(textObj->style()); 6677 remainingText->setStyle(textObj->style());
6670 if (remainingText->node()) 6678 if (remainingText->node())
6671 remainingText->node()->setRenderer(remainingText); 6679 remainingText->node()->setRenderer(remainingText);
6672 6680
6673 firstLetterContainer->addChild(remainingText, textObj); 6681 firstLetterContainer->addChild(remainingText, textObj);
6674 firstLetterContainer->removeChild(textObj); 6682 firstLetterContainer->removeChild(textObj);
(...skipping 19 matching lines...) Expand all
6694 return; 6702 return;
6695 6703
6696 // FIXME: We need to destroy the first-letter object if it is no longer the first child. Need to find 6704 // FIXME: We need to destroy the first-letter object if it is no longer the first child. Need to find
6697 // an efficient way to check for that situation though before implementing a nything. 6705 // an efficient way to check for that situation though before implementing a nything.
6698 RenderObject* firstLetterBlock = findFirstLetterBlock(this); 6706 RenderObject* firstLetterBlock = findFirstLetterBlock(this);
6699 if (!firstLetterBlock) 6707 if (!firstLetterBlock)
6700 return; 6708 return;
6701 6709
6702 // Drill into inlines looking for our first text child. 6710 // Drill into inlines looking for our first text child.
6703 RenderObject* currChild = firstLetterBlock->firstChild(); 6711 RenderObject* currChild = firstLetterBlock->firstChild();
6712 RenderObject* firstLetter = currChild;
6713
6704 while (currChild) { 6714 while (currChild) {
6705 if (currChild->isText()) 6715 if (currChild->isText())
6706 break; 6716 break;
6707 if (currChild->isListMarker()) 6717 if (currChild->isListMarker())
6708 currChild = currChild->nextSibling(); 6718 currChild = currChild->nextSibling();
6709 else if (currChild->isFloatingOrOutOfFlowPositioned()) { 6719 else if (currChild->isFloatingOrOutOfFlowPositioned()) {
6710 if (currChild->style()->styleType() == FIRST_LETTER) { 6720 if (currChild->style()->styleType() == FIRST_LETTER) {
6711 currChild = currChild->firstChild(); 6721 currChild = currChild->firstChild();
6712 break; 6722 break;
6713 } 6723 }
6714 currChild = currChild->nextSibling(); 6724 currChild = currChild->nextSibling();
6715 } else if (currChild->isReplaced() || currChild->isRenderButton() || cur rChild->isMenuList()) 6725 } else if (currChild->isReplaced() || currChild->isRenderButton() || cur rChild->isMenuList())
6716 break; 6726 break;
6717 else if (currChild->style()->hasPseudoStyle(FIRST_LETTER) && currChild-> canHaveGeneratedChildren()) { 6727 else if (currChild->style()->hasPseudoStyle(FIRST_LETTER) && currChild-> canHaveGeneratedChildren()) {
6718 // We found a lower-level node with first-letter, which supersedes t he higher-level style 6728 // We found a lower-level node with first-letter, which supersedes t he higher-level style
6719 firstLetterBlock = currChild; 6729 firstLetterBlock = currChild;
6720 currChild = currChild->firstChild(); 6730 currChild = currChild->firstChild();
6721 } else 6731 } else
6722 currChild = currChild->firstChild(); 6732 currChild = currChild->firstChild();
6723 } 6733 }
6724 6734
6725 if (!currChild) 6735 if (!currChild)
6726 return; 6736 return;
6727 6737
6728 // If the child already has style, then it has already been created, so we j ust want 6738 // If the child already has style, then it has already been created, so we j ust want
6729 // to update it. 6739 // to update it.
6730 if (currChild->parent()->style()->styleType() == FIRST_LETTER) { 6740 if (currChild->parent()->style()->styleType() == FIRST_LETTER) {
6741 RenderText* remainingText = toRenderText(currChild->parent()->nextSiblin g());
6742 // When the first line is changed by adding a new text at its start,
6743 // the first letter has to be updated.
6744 if (toRenderBoxModelObject(firstLetter)->firstLetterRemainingText() != r emainingText) {
6745 RenderText* firstLetterText = toRenderText(currChild);
6746 RefPtr<StringImpl> updatedTextImp = remainingText->originalText();
esprehn 2013/05/06 20:43:58 Just use String. A String is just a RefPtr to a St
6747 ASSERT(updatedTextImp);
esprehn 2013/05/06 20:43:58 This assert should be inside whiteSpaceLength
6748 unsigned length = 0;
6749 if (updatedTextImp && updatedTextImp->length() > 0)
esprehn 2013/05/06 20:43:58 This check should be inside whiteSpaceLength() and
6750 length = whiteSpaceLength(updatedTextImp);
6751
6752 firstLetterText->setText(updatedTextImp->substring(0, length));
6753 remainingText->setText(updatedTextImp->substring(length));
6754
6755 RenderObject* oldRemainingText = currChild->parent()->nextSibling()- >nextSibling();
esprehn 2013/05/06 20:43:58 This doesn't look safe at all. How do you know you
6756 // Replace the previous remaining text with the original text.
6757 // because it doesn't have the first letter.
6758 if (oldRemainingText->isText()) {
6759 RefPtr<StringImpl> oldString = toText(oldRemainingText->node())- >dataImpl();
esprehn 2013/05/06 20:43:58 This is going to crash if it's an anonymous text r
6760
6761 // Before calling setText, we need to set m_firstLetter to 0 in order not to delete it.
6762 if (toRenderText(oldRemainingText)->isTextFragment())
6763 toRenderTextFragment(oldRemainingText)->setFirstLetter(0);
6764
6765 toRenderText(oldRemainingText)->setText(oldString);
6766 }
6767 toRenderBoxModelObject(firstLetter)->setFirstLetterRemainingText(rem ainingText);
6768 }
6769
6731 updateFirstLetterStyle(firstLetterBlock, currChild); 6770 updateFirstLetterStyle(firstLetterBlock, currChild);
6732 return; 6771 return;
6733 } 6772 }
6734 6773
6735 if (!currChild->isText() || currChild->isBR()) 6774 if (!currChild->isText() || currChild->isBR())
6736 return; 6775 return;
6737 6776
6738 // Our layout state is not valid for the repaints we are going to trigger by 6777 // Our layout state is not valid for the repaints we are going to trigger by
6739 // adding and removing children of firstLetterContainer. 6778 // adding and removing children of firstLetterContainer.
6740 LayoutStateDisabler layoutStateDisabler(view()); 6779 LayoutStateDisabler layoutStateDisabler(view());
(...skipping 1373 matching lines...) Expand 10 before | Expand all | Expand 10 after
8114 { 8153 {
8115 memoryInstrumentation->addRootObject(gColumnInfoMap, WebCoreMemoryTypes::Ren deringStructures); 8154 memoryInstrumentation->addRootObject(gColumnInfoMap, WebCoreMemoryTypes::Ren deringStructures);
8116 memoryInstrumentation->addRootObject(gPositionedDescendantsMap, WebCoreMemor yTypes::RenderingStructures); 8155 memoryInstrumentation->addRootObject(gPositionedDescendantsMap, WebCoreMemor yTypes::RenderingStructures);
8117 memoryInstrumentation->addRootObject(gPercentHeightDescendantsMap, WebCoreMe moryTypes::RenderingStructures); 8156 memoryInstrumentation->addRootObject(gPercentHeightDescendantsMap, WebCoreMe moryTypes::RenderingStructures);
8118 memoryInstrumentation->addRootObject(gPositionedContainerMap, WebCoreMemoryT ypes::RenderingStructures); 8157 memoryInstrumentation->addRootObject(gPositionedContainerMap, WebCoreMemoryT ypes::RenderingStructures);
8119 memoryInstrumentation->addRootObject(gPercentHeightContainerMap, WebCoreMemo ryTypes::RenderingStructures); 8158 memoryInstrumentation->addRootObject(gPercentHeightContainerMap, WebCoreMemo ryTypes::RenderingStructures);
8120 memoryInstrumentation->addRootObject(gDelayedUpdateScrollInfoSet, WebCoreMem oryTypes::RenderingStructures); 8159 memoryInstrumentation->addRootObject(gDelayedUpdateScrollInfoSet, WebCoreMem oryTypes::RenderingStructures);
8121 } 8160 }
8122 8161
8123 } // namespace WebCore 8162 } // namespace WebCore
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698