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 |