Index: WebCore/rendering/RenderBlock.cpp |
=================================================================== |
--- WebCore/rendering/RenderBlock.cpp (revision 67718) |
+++ WebCore/rendering/RenderBlock.cpp (working copy) |
@@ -5089,6 +5089,16 @@ |
return firstLineBlock; |
} |
+static RenderStyle* styleForFirstLetter(RenderObject* firstLetterBlock, RenderObject* firstLetterContainer) |
+{ |
+ RenderStyle* pseudoStyle = firstLetterBlock->getCachedPseudoStyle(FIRST_LETTER, firstLetterContainer->firstLineStyle()); |
+ // Force inline display (except for floating first-letters). |
+ pseudoStyle->setDisplay(pseudoStyle->isFloating() ? BLOCK : INLINE); |
+ // CSS2 says first-letter can't be positioned. |
+ pseudoStyle->setPosition(StaticPosition); |
+ return pseudoStyle; |
+} |
+ |
void RenderBlock::updateFirstLetter() |
{ |
if (!document()->usesFirstLetterRules()) |
@@ -5138,84 +5148,110 @@ |
if (!currChild) |
return; |
- RenderObject* firstLetterContainer = currChild->parent(); |
- |
// If the child already has style, then it has already been created, so we just want |
// to update it. |
- if (firstLetterContainer->style()->styleType() == FIRST_LETTER) { |
- RenderStyle* pseudo = firstLetterBlock->getCachedPseudoStyle(FIRST_LETTER, |
- firstLetterContainer->parent()->firstLineStyle()); |
- firstLetterContainer->setStyle(pseudo); |
- for (RenderObject* genChild = firstLetterContainer->firstChild(); genChild; genChild = genChild->nextSibling()) { |
+ if (currChild->parent()->style()->styleType() == FIRST_LETTER) { |
+ RenderObject* firstLetter = currChild->parent(); |
+ RenderObject* firstLetterContainer = firstLetter->parent(); |
+ RenderStyle* pseudoStyle = styleForFirstLetter(firstLetterBlock, firstLetterContainer); |
+ |
+ if (Node::diff(firstLetter->style(), pseudoStyle) == Node::Detach) { |
+ // The first-letter renderer needs to be replaced. Create a new renderer of the right type. |
+ RenderObject* newFirstLetter; |
+ if (pseudoStyle->display() == INLINE) |
+ newFirstLetter = new (renderArena()) RenderInline(document()); |
+ else |
+ newFirstLetter = new (renderArena()) RenderBlock(document()); |
+ newFirstLetter->setStyle(pseudoStyle); |
+ |
+ // Move the first letter into the new renderer. |
+ view()->disableLayoutState(); |
+ while (RenderObject* child = firstLetter->firstChild()) { |
+ if (child->isText()) |
+ toRenderText(child)->dirtyLineBoxes(true); |
+ firstLetter->removeChild(child); |
+ newFirstLetter->addChild(child, 0); |
+ } |
+ RenderTextFragment* remainingText = toRenderTextFragment(firstLetter->nextSibling()); |
+ ASSERT(remainingText->node()->renderer() == remainingText); |
+ // Replace the old renderer with the new one. |
+ remainingText->setFirstLetter(newFirstLetter); |
+ firstLetter->destroy(); |
+ firstLetter = newFirstLetter; |
+ firstLetterContainer->addChild(firstLetter, remainingText); |
+ view()->enableLayoutState(); |
+ } else |
+ firstLetter->setStyle(pseudoStyle); |
+ |
+ for (RenderObject* genChild = firstLetter->firstChild(); genChild; genChild = genChild->nextSibling()) { |
if (genChild->isText()) |
- genChild->setStyle(pseudo); |
+ genChild->setStyle(pseudoStyle); |
} |
+ |
return; |
} |
+ if (!currChild->isText() || currChild->isBR()) |
+ return; |
+ |
// If the child does not already have style, we create it here. |
- if (currChild->isText() && !currChild->isBR() && currChild->parent()->style()->styleType() != FIRST_LETTER) { |
- // Our layout state is not valid for the repaints we are going to trigger by |
- // adding and removing children of firstLetterContainer. |
- view()->disableLayoutState(); |
+ RenderObject* firstLetterContainer = currChild->parent(); |
- RenderText* textObj = toRenderText(currChild); |
+ // Our layout state is not valid for the repaints we are going to trigger by |
+ // adding and removing children of firstLetterContainer. |
+ view()->disableLayoutState(); |
- // Create our pseudo style now that we have our firstLetterContainer determined. |
- RenderStyle* pseudoStyle = firstLetterBlock->getCachedPseudoStyle(FIRST_LETTER, |
- firstLetterContainer->firstLineStyle()); |
- |
- // Force inline display (except for floating first-letters) |
- pseudoStyle->setDisplay(pseudoStyle->isFloating() ? BLOCK : INLINE); |
- pseudoStyle->setPosition(StaticPosition); // CSS2 says first-letter can't be positioned. |
- |
- RenderObject* firstLetter = 0; |
- if (pseudoStyle->display() == INLINE) |
- firstLetter = new (renderArena()) RenderInline(document()); |
- else |
- firstLetter = new (renderArena()) RenderBlock(document()); |
- firstLetter->setStyle(pseudoStyle); |
- firstLetterContainer->addChild(firstLetter, currChild); |
- |
- // The original string is going to be either a generated content string or a DOM node's |
- // string. We want the original string before it got transformed in case first-letter has |
- // no text-transform or a different text-transform applied to it. |
- RefPtr<StringImpl> oldText = textObj->originalText(); |
- ASSERT(oldText); |
- |
- if (oldText && oldText->length() > 0) { |
- unsigned int length = 0; |
- |
- // account for leading spaces and punctuation |
- while (length < oldText->length() && (isSpaceOrNewline((*oldText)[length]) || Unicode::isPunct((*oldText)[length]))) |
- length++; |
- |
- // account for first letter |
+ RenderText* textObj = toRenderText(currChild); |
+ |
+ // Create our pseudo style now that we have our firstLetterContainer determined. |
+ RenderStyle* pseudoStyle = styleForFirstLetter(firstLetterBlock, firstLetterContainer); |
+ |
+ RenderObject* firstLetter = 0; |
+ if (pseudoStyle->display() == INLINE) |
+ firstLetter = new (renderArena()) RenderInline(document()); |
+ else |
+ firstLetter = new (renderArena()) RenderBlock(document()); |
+ firstLetter->setStyle(pseudoStyle); |
+ firstLetterContainer->addChild(firstLetter, currChild); |
+ |
+ // The original string is going to be either a generated content string or a DOM node's |
+ // string. We want the original string before it got transformed in case first-letter has |
+ // no text-transform or a different text-transform applied to it. |
+ RefPtr<StringImpl> oldText = textObj->originalText(); |
+ ASSERT(oldText); |
+ |
+ if (oldText && oldText->length() > 0) { |
+ unsigned length = 0; |
+ |
+ // account for leading spaces and punctuation |
+ while (length < oldText->length() && (isSpaceOrNewline((*oldText)[length]) || Unicode::isPunct((*oldText)[length]))) |
length++; |
- |
- // construct text fragment for the text after the first letter |
- // NOTE: this might empty |
- RenderTextFragment* remainingText = |
- new (renderArena()) RenderTextFragment(textObj->node() ? textObj->node() : textObj->document(), oldText.get(), length, oldText->length() - length); |
- remainingText->setStyle(textObj->style()); |
- if (remainingText->node()) |
- remainingText->node()->setRenderer(remainingText); |
- |
- RenderObject* nextObj = textObj->nextSibling(); |
- firstLetterContainer->removeChild(textObj); |
- firstLetterContainer->addChild(remainingText, nextObj); |
- remainingText->setFirstLetter(firstLetter); |
- |
- // construct text fragment for the first letter |
- RenderTextFragment* letter = |
- new (renderArena()) RenderTextFragment(remainingText->node() ? remainingText->node() : remainingText->document(), oldText.get(), 0, length); |
- letter->setStyle(pseudoStyle); |
- firstLetter->addChild(letter); |
- textObj->destroy(); |
- } |
- view()->enableLayoutState(); |
+ // account for first letter |
+ length++; |
+ |
+ // construct text fragment for the text after the first letter |
+ // NOTE: this might empty |
+ RenderTextFragment* remainingText = |
+ new (renderArena()) RenderTextFragment(textObj->node() ? textObj->node() : textObj->document(), oldText.get(), length, oldText->length() - length); |
+ remainingText->setStyle(textObj->style()); |
+ if (remainingText->node()) |
+ remainingText->node()->setRenderer(remainingText); |
+ |
+ RenderObject* nextObj = textObj->nextSibling(); |
+ firstLetterContainer->removeChild(textObj); |
+ firstLetterContainer->addChild(remainingText, nextObj); |
+ remainingText->setFirstLetter(firstLetter); |
+ |
+ // construct text fragment for the first letter |
+ RenderTextFragment* letter = |
+ new (renderArena()) RenderTextFragment(remainingText->node() ? remainingText->node() : remainingText->document(), oldText.get(), 0, length); |
+ letter->setStyle(pseudoStyle); |
+ firstLetter->addChild(letter); |
+ |
+ textObj->destroy(); |
} |
+ view()->enableLayoutState(); |
} |
// Helper methods for obtaining the last line, computing line counts and heights for line counts |