| OLD | NEW |
| 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 Apple Inc. All r
ights reserved. | 5 * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Apple Inc. All r
ights 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 5071 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5082 ASSERT(parentBlock->isRenderBlock()); | 5082 ASSERT(parentBlock->isRenderBlock()); |
| 5083 firstLineBlock = toRenderBlock(parentBlock); | 5083 firstLineBlock = toRenderBlock(parentBlock); |
| 5084 } | 5084 } |
| 5085 | 5085 |
| 5086 if (!hasPseudo) | 5086 if (!hasPseudo) |
| 5087 return 0; | 5087 return 0; |
| 5088 | 5088 |
| 5089 return firstLineBlock; | 5089 return firstLineBlock; |
| 5090 } | 5090 } |
| 5091 | 5091 |
| 5092 static RenderStyle* styleForFirstLetter(RenderObject* firstLetterBlock, RenderOb
ject* firstLetterContainer) |
| 5093 { |
| 5094 RenderStyle* pseudoStyle = firstLetterBlock->getCachedPseudoStyle(FIRST_LETT
ER, firstLetterContainer->firstLineStyle()); |
| 5095 // Force inline display (except for floating first-letters). |
| 5096 pseudoStyle->setDisplay(pseudoStyle->isFloating() ? BLOCK : INLINE); |
| 5097 // CSS2 says first-letter can't be positioned. |
| 5098 pseudoStyle->setPosition(StaticPosition); |
| 5099 return pseudoStyle; |
| 5100 } |
| 5101 |
| 5092 void RenderBlock::updateFirstLetter() | 5102 void RenderBlock::updateFirstLetter() |
| 5093 { | 5103 { |
| 5094 if (!document()->usesFirstLetterRules()) | 5104 if (!document()->usesFirstLetterRules()) |
| 5095 return; | 5105 return; |
| 5096 // Don't recur | 5106 // Don't recur |
| 5097 if (style()->styleType() == FIRST_LETTER) | 5107 if (style()->styleType() == FIRST_LETTER) |
| 5098 return; | 5108 return; |
| 5099 | 5109 |
| 5100 // FIXME: We need to destroy the first-letter object if it is no longer the
first child. Need to find | 5110 // FIXME: We need to destroy the first-letter object if it is no longer the
first child. Need to find |
| 5101 // an efficient way to check for that situation though before implementing a
nything. | 5111 // an efficient way to check for that situation though before implementing a
nything. |
| (...skipping 29 matching lines...) Expand all Loading... |
| 5131 currChild = currChild->firstChild(); | 5141 currChild = currChild->firstChild(); |
| 5132 } | 5142 } |
| 5133 | 5143 |
| 5134 // Get list markers out of the way. | 5144 // Get list markers out of the way. |
| 5135 while (currChild && currChild->isListMarker()) | 5145 while (currChild && currChild->isListMarker()) |
| 5136 currChild = currChild->nextSibling(); | 5146 currChild = currChild->nextSibling(); |
| 5137 | 5147 |
| 5138 if (!currChild) | 5148 if (!currChild) |
| 5139 return; | 5149 return; |
| 5140 | 5150 |
| 5141 RenderObject* firstLetterContainer = currChild->parent(); | |
| 5142 | |
| 5143 // If the child already has style, then it has already been created, so we j
ust want | 5151 // If the child already has style, then it has already been created, so we j
ust want |
| 5144 // to update it. | 5152 // to update it. |
| 5145 if (firstLetterContainer->style()->styleType() == FIRST_LETTER) { | 5153 if (currChild->parent()->style()->styleType() == FIRST_LETTER) { |
| 5146 RenderStyle* pseudo = firstLetterBlock->getCachedPseudoStyle(FIRST_LETTE
R, | 5154 RenderObject* firstLetter = currChild->parent(); |
| 5147 firstLetter
Container->parent()->firstLineStyle()); | 5155 RenderObject* firstLetterContainer = firstLetter->parent(); |
| 5148 firstLetterContainer->setStyle(pseudo); | 5156 RenderStyle* pseudoStyle = styleForFirstLetter(firstLetterBlock, firstLe
tterContainer); |
| 5149 for (RenderObject* genChild = firstLetterContainer->firstChild(); genChi
ld; genChild = genChild->nextSibling()) { | 5157 |
| 5158 if (Node::diff(firstLetter->style(), pseudoStyle) == Node::Detach) { |
| 5159 // The first-letter renderer needs to be replaced. Create a new rend
erer of the right type. |
| 5160 RenderObject* newFirstLetter; |
| 5161 if (pseudoStyle->display() == INLINE) |
| 5162 newFirstLetter = new (renderArena()) RenderInline(document()); |
| 5163 else |
| 5164 newFirstLetter = new (renderArena()) RenderBlock(document()); |
| 5165 newFirstLetter->setStyle(pseudoStyle); |
| 5166 |
| 5167 // Move the first letter into the new renderer. |
| 5168 view()->disableLayoutState(); |
| 5169 while (RenderObject* child = firstLetter->firstChild()) { |
| 5170 if (child->isText()) |
| 5171 toRenderText(child)->dirtyLineBoxes(true); |
| 5172 firstLetter->removeChild(child); |
| 5173 newFirstLetter->addChild(child, 0); |
| 5174 } |
| 5175 RenderTextFragment* remainingText = toRenderTextFragment(firstLetter
->nextSibling()); |
| 5176 ASSERT(remainingText->node()->renderer() == remainingText); |
| 5177 // Replace the old renderer with the new one. |
| 5178 remainingText->setFirstLetter(newFirstLetter); |
| 5179 firstLetter->destroy(); |
| 5180 firstLetter = newFirstLetter; |
| 5181 firstLetterContainer->addChild(firstLetter, remainingText); |
| 5182 view()->enableLayoutState(); |
| 5183 } else |
| 5184 firstLetter->setStyle(pseudoStyle); |
| 5185 |
| 5186 for (RenderObject* genChild = firstLetter->firstChild(); genChild; genCh
ild = genChild->nextSibling()) { |
| 5150 if (genChild->isText()) | 5187 if (genChild->isText()) |
| 5151 genChild->setStyle(pseudo); | 5188 genChild->setStyle(pseudoStyle); |
| 5152 } | 5189 } |
| 5190 |
| 5153 return; | 5191 return; |
| 5154 } | 5192 } |
| 5155 | 5193 |
| 5194 if (!currChild->isText() || currChild->isBR()) |
| 5195 return; |
| 5196 |
| 5156 // If the child does not already have style, we create it here. | 5197 // If the child does not already have style, we create it here. |
| 5157 if (currChild->isText() && !currChild->isBR() && currChild->parent()->style(
)->styleType() != FIRST_LETTER) { | 5198 RenderObject* firstLetterContainer = currChild->parent(); |
| 5158 // Our layout state is not valid for the repaints we are going to trigge
r by | |
| 5159 // adding and removing children of firstLetterContainer. | |
| 5160 view()->disableLayoutState(); | |
| 5161 | 5199 |
| 5162 RenderText* textObj = toRenderText(currChild); | 5200 // Our layout state is not valid for the repaints we are going to trigger by |
| 5201 // adding and removing children of firstLetterContainer. |
| 5202 view()->disableLayoutState(); |
| 5163 | 5203 |
| 5164 // Create our pseudo style now that we have our firstLetterContainer det
ermined. | 5204 RenderText* textObj = toRenderText(currChild); |
| 5165 RenderStyle* pseudoStyle = firstLetterBlock->getCachedPseudoStyle(FIRST_
LETTER, | 5205 |
| 5166 firstL
etterContainer->firstLineStyle()); | 5206 // Create our pseudo style now that we have our firstLetterContainer determi
ned. |
| 5207 RenderStyle* pseudoStyle = styleForFirstLetter(firstLetterBlock, firstLetter
Container); |
| 5208 |
| 5209 RenderObject* firstLetter = 0; |
| 5210 if (pseudoStyle->display() == INLINE) |
| 5211 firstLetter = new (renderArena()) RenderInline(document()); |
| 5212 else |
| 5213 firstLetter = new (renderArena()) RenderBlock(document()); |
| 5214 firstLetter->setStyle(pseudoStyle); |
| 5215 firstLetterContainer->addChild(firstLetter, currChild); |
| 5216 |
| 5217 // The original string is going to be either a generated content string or a
DOM node's |
| 5218 // string. We want the original string before it got transformed in case fi
rst-letter has |
| 5219 // no text-transform or a different text-transform applied to it. |
| 5220 RefPtr<StringImpl> oldText = textObj->originalText(); |
| 5221 ASSERT(oldText); |
| 5222 |
| 5223 if (oldText && oldText->length() > 0) { |
| 5224 unsigned length = 0; |
| 5225 |
| 5226 // account for leading spaces and punctuation |
| 5227 while (length < oldText->length() && (isSpaceOrNewline((*oldText)[length
]) || Unicode::isPunct((*oldText)[length]))) |
| 5228 length++; |
| 5229 |
| 5230 // account for first letter |
| 5231 length++; |
| 5232 |
| 5233 // construct text fragment for the text after the first letter |
| 5234 // NOTE: this might empty |
| 5235 RenderTextFragment* remainingText = |
| 5236 new (renderArena()) RenderTextFragment(textObj->node() ? textObj->no
de() : textObj->document(), oldText.get(), length, oldText->length() - length); |
| 5237 remainingText->setStyle(textObj->style()); |
| 5238 if (remainingText->node()) |
| 5239 remainingText->node()->setRenderer(remainingText); |
| 5240 |
| 5241 RenderObject* nextObj = textObj->nextSibling(); |
| 5242 firstLetterContainer->removeChild(textObj); |
| 5243 firstLetterContainer->addChild(remainingText, nextObj); |
| 5244 remainingText->setFirstLetter(firstLetter); |
| 5167 | 5245 |
| 5168 // Force inline display (except for floating first-letters) | 5246 // construct text fragment for the first letter |
| 5169 pseudoStyle->setDisplay(pseudoStyle->isFloating() ? BLOCK : INLINE); | 5247 RenderTextFragment* letter = |
| 5170 pseudoStyle->setPosition(StaticPosition); // CSS2 says first-letter can'
t be positioned. | 5248 new (renderArena()) RenderTextFragment(remainingText->node() ? remai
ningText->node() : remainingText->document(), oldText.get(), 0, length); |
| 5171 | 5249 letter->setStyle(pseudoStyle); |
| 5172 RenderObject* firstLetter = 0; | 5250 firstLetter->addChild(letter); |
| 5173 if (pseudoStyle->display() == INLINE) | |
| 5174 firstLetter = new (renderArena()) RenderInline(document()); | |
| 5175 else | |
| 5176 firstLetter = new (renderArena()) RenderBlock(document()); | |
| 5177 firstLetter->setStyle(pseudoStyle); | |
| 5178 firstLetterContainer->addChild(firstLetter, currChild); | |
| 5179 | |
| 5180 // The original string is going to be either a generated content string
or a DOM node's | |
| 5181 // string. We want the original string before it got transformed in cas
e first-letter has | |
| 5182 // no text-transform or a different text-transform applied to it. | |
| 5183 RefPtr<StringImpl> oldText = textObj->originalText(); | |
| 5184 ASSERT(oldText); | |
| 5185 | |
| 5186 if (oldText && oldText->length() > 0) { | |
| 5187 unsigned int length = 0; | |
| 5188 | |
| 5189 // account for leading spaces and punctuation | |
| 5190 while (length < oldText->length() && (isSpaceOrNewline((*oldText)[le
ngth]) || Unicode::isPunct((*oldText)[length]))) | |
| 5191 length++; | |
| 5192 | |
| 5193 // account for first letter | |
| 5194 length++; | |
| 5195 | |
| 5196 // construct text fragment for the text after the first letter | |
| 5197 // NOTE: this might empty | |
| 5198 RenderTextFragment* remainingText = | |
| 5199 new (renderArena()) RenderTextFragment(textObj->node() ? textObj
->node() : textObj->document(), oldText.get(), length, oldText->length() - lengt
h); | |
| 5200 remainingText->setStyle(textObj->style()); | |
| 5201 if (remainingText->node()) | |
| 5202 remainingText->node()->setRenderer(remainingText); | |
| 5203 | |
| 5204 RenderObject* nextObj = textObj->nextSibling(); | |
| 5205 firstLetterContainer->removeChild(textObj); | |
| 5206 firstLetterContainer->addChild(remainingText, nextObj); | |
| 5207 remainingText->setFirstLetter(firstLetter); | |
| 5208 | |
| 5209 // construct text fragment for the first letter | |
| 5210 RenderTextFragment* letter = | |
| 5211 new (renderArena()) RenderTextFragment(remainingText->node() ? r
emainingText->node() : remainingText->document(), oldText.get(), 0, length); | |
| 5212 letter->setStyle(pseudoStyle); | |
| 5213 firstLetter->addChild(letter); | |
| 5214 | 5251 |
| 5215 textObj->destroy(); | 5252 textObj->destroy(); |
| 5216 } | |
| 5217 view()->enableLayoutState(); | |
| 5218 } | 5253 } |
| 5254 view()->enableLayoutState(); |
| 5219 } | 5255 } |
| 5220 | 5256 |
| 5221 // Helper methods for obtaining the last line, computing line counts and heights
for line counts | 5257 // Helper methods for obtaining the last line, computing line counts and heights
for line counts |
| 5222 // (crawling into blocks). | 5258 // (crawling into blocks). |
| 5223 static bool shouldCheckLines(RenderObject* obj) | 5259 static bool shouldCheckLines(RenderObject* obj) |
| 5224 { | 5260 { |
| 5225 return !obj->isFloatingOrPositioned() && !obj->isRunIn() && | 5261 return !obj->isFloatingOrPositioned() && !obj->isRunIn() && |
| 5226 obj->isBlockFlow() && obj->style()->height().isAuto() && | 5262 obj->isBlockFlow() && obj->style()->height().isAuto() && |
| 5227 (!obj->isFlexibleBox() || obj->style()->boxOrient() == VERTICAL); | 5263 (!obj->isFlexibleBox() || obj->style()->boxOrient() == VERTICAL); |
| 5228 } | 5264 } |
| (...skipping 455 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5684 else if (isAnonymous()) | 5720 else if (isAnonymous()) |
| 5685 return "RenderBlock (generated)"; | 5721 return "RenderBlock (generated)"; |
| 5686 if (isRelPositioned()) | 5722 if (isRelPositioned()) |
| 5687 return "RenderBlock (relative positioned)"; | 5723 return "RenderBlock (relative positioned)"; |
| 5688 if (isRunIn()) | 5724 if (isRunIn()) |
| 5689 return "RenderBlock (run-in)"; | 5725 return "RenderBlock (run-in)"; |
| 5690 return "RenderBlock"; | 5726 return "RenderBlock"; |
| 5691 } | 5727 } |
| 5692 | 5728 |
| 5693 } // namespace WebCore | 5729 } // namespace WebCore |
| OLD | NEW |