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, 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 * Copyright (C) 2014 Samsung Electronics. All rights reserved. | |
7 * | 8 * |
8 * This library is free software; you can redistribute it and/or | 9 * This library is free software; you can redistribute it and/or |
9 * modify it under the terms of the GNU Library General Public | 10 * modify it under the terms of the GNU Library General Public |
10 * License as published by the Free Software Foundation; either | 11 * License as published by the Free Software Foundation; either |
11 * version 2 of the License, or (at your option) any later version. | 12 * version 2 of the License, or (at your option) any later version. |
12 * | 13 * |
13 * This library is distributed in the hope that it will be useful, | 14 * This library is distributed in the hope that it will be useful, |
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of | 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
16 * Library General Public License for more details. | 17 * Library General Public License for more details. |
(...skipping 4082 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
4099 firstLetterContainer->addChild(firstLetter, nextSibling); | 4100 firstLetterContainer->addChild(firstLetter, nextSibling); |
4100 } else | 4101 } else |
4101 firstLetter->setStyle(pseudoStyle); | 4102 firstLetter->setStyle(pseudoStyle); |
4102 | 4103 |
4103 for (RenderObject* genChild = firstLetter->firstChild(); genChild; genChild = genChild->nextSibling()) { | 4104 for (RenderObject* genChild = firstLetter->firstChild(); genChild; genChild = genChild->nextSibling()) { |
4104 if (genChild->isText()) | 4105 if (genChild->isText()) |
4105 genChild->setStyle(pseudoStyle); | 4106 genChild->setStyle(pseudoStyle); |
4106 } | 4107 } |
4107 } | 4108 } |
4108 | 4109 |
4109 static inline unsigned firstLetterLength(const String& text) | |
4110 { | |
4111 unsigned length = 0; | |
4112 unsigned textLength = text.length(); | |
4113 | |
4114 // Account for leading spaces first. | |
4115 while (length < textLength && isSpaceForFirstLetter(text[length])) | |
4116 length++; | |
4117 | |
4118 // Now account for leading punctuation. | |
4119 while (length < textLength && isPunctuationForFirstLetter(text[length])) | |
4120 length++; | |
4121 | |
4122 // Bail if we didn't find a letter before the end of the text or before a sp ace. | |
4123 if (isSpaceForFirstLetter(text[length]) || (textLength && length == textLeng th)) | |
4124 return 0; | |
4125 | |
4126 // Account the next character for first letter. | |
4127 length++; | |
4128 | |
4129 // Keep looking allowed punctuation for the :first-letter. | |
4130 for (unsigned scanLength = length; scanLength < textLength; ++scanLength) { | |
4131 UChar c = text[scanLength]; | |
4132 | |
4133 if (!isPunctuationForFirstLetter(c)) | |
4134 break; | |
4135 | |
4136 length = scanLength + 1; | |
4137 } | |
4138 | |
4139 // FIXME: If textLength is 0, length may still be 1! | |
4140 return length; | |
4141 } | |
4142 | |
4143 void RenderBlock::createFirstLetterRenderer(RenderObject* firstLetterBlock, Rend erObject* currentChild, unsigned length) | 4110 void RenderBlock::createFirstLetterRenderer(RenderObject* firstLetterBlock, Rend erObject* currentChild, unsigned length) |
4144 { | 4111 { |
4145 ASSERT(length && currentChild->isText()); | 4112 ASSERT(length && currentChild->isText()); |
4146 | 4113 |
4147 RenderObject* firstLetterContainer = currentChild->parent(); | 4114 RenderObject* firstLetterContainer = currentChild->parent(); |
4148 RenderStyle* pseudoStyle = styleForFirstLetter(firstLetterBlock, firstLetter Container); | 4115 RenderStyle* pseudoStyle = styleForFirstLetter(firstLetterBlock, firstLetter Container); |
4149 RenderObject* firstLetter = 0; | 4116 RenderObject* firstLetter = 0; |
4150 if (pseudoStyle->display() == INLINE) | 4117 if (pseudoStyle->display() == INLINE) |
4151 firstLetter = RenderInline::createAnonymous(&document()); | 4118 firstLetter = RenderInline::createAnonymous(&document()); |
4152 else | 4119 else |
(...skipping 24 matching lines...) Expand all Loading... | |
4177 | 4144 |
4178 // construct text fragment for the first letter | 4145 // construct text fragment for the first letter |
4179 RenderTextFragment* letter = | 4146 RenderTextFragment* letter = |
4180 new RenderTextFragment(remainingText->node() ? remainingText->node() : & remainingText->document(), oldText.impl(), 0, length); | 4147 new RenderTextFragment(remainingText->node() ? remainingText->node() : & remainingText->document(), oldText.impl(), 0, length); |
4181 letter->setStyle(pseudoStyle); | 4148 letter->setStyle(pseudoStyle); |
4182 firstLetter->addChild(letter); | 4149 firstLetter->addChild(letter); |
4183 | 4150 |
4184 textObj->destroy(); | 4151 textObj->destroy(); |
4185 } | 4152 } |
4186 | 4153 |
4154 static String getRendererTextForFirstLetter(RenderObject* renderer) | |
eseidel
2014/03/26 15:31:52
We don't normally use "get" for getters in Blink s
| |
4155 { | |
4156 ASSERT(renderer->isText()); | |
4157 | |
4158 RenderText* textRenderer = toRenderText(renderer); | |
4159 String result = textRenderer->originalText(); | |
4160 | |
4161 // BR and Word breaks are not allowed to be part of the first-letter | |
4162 // pseudo element, so we don't fallback to text() in those case. | |
4163 if (!result && !textRenderer->isBR() && !textRenderer->isWordBreak()) | |
4164 result = textRenderer->text(); | |
4165 | |
4166 return result; | |
4167 } | |
4168 | |
4169 // This helper function fills the vector of RenderObjects with the ones that wou ld be considered | |
4170 // as part of the first-letter pseudo element and returns the number of characte rs in the last | |
4171 // renderer found that should be considered as part of such a pseudo element (th e other renderers | |
4172 // in the Vector will be considered "in full"). Also, this function might update the firstLetterBlock | |
4173 // pointer if a lower-level node with first-letter style is found while traversi ng the subtree under | |
4174 // the RenderObject originally passed through that parameter. | |
4175 static unsigned findTextRenderersForFirstLetterBlock(RenderObject*& firstLetterB lock, Vector<RenderObject*>& renderers) | |
4176 { | |
4177 String text; | |
4178 unsigned textLength = 0; | |
4179 unsigned length = 0; | |
4180 unsigned previousLength = 0; | |
4181 bool leadingSpacesChecked = false; | |
4182 bool leadingPunctuationChecked = false; | |
4183 bool firstLetterRenderersFound = false; | |
4184 | |
4185 // Drill into inlines looking for the render objects to be transformed into first-letter pseudoelements. | |
4186 RenderObject* currChild = firstLetterBlock->firstChild(); | |
4187 while (currChild) { | |
4188 if (currChild->isText()) { | |
4189 text = getRendererTextForFirstLetter(currChild); | |
eseidel
2014/03/26 15:31:22
Please break this block out into its own function.
| |
4190 textLength = text.length(); | |
4191 previousLength = length; | |
4192 length = 0; | |
4193 | |
4194 // Early checks in case we encounter the wrong characters in the wro ng place. | |
4195 if ((leadingSpacesChecked && isSpaceForFirstLetter(text[length])) | |
4196 || (firstLetterRenderersFound && !isPunctuationForFirstLetter(te xt[length]))) | |
4197 break; | |
4198 | |
4199 if (!leadingSpacesChecked && length < textLength) { | |
4200 while (length < textLength && isSpaceForFirstLetter(text[length] )) | |
4201 length++; | |
4202 | |
4203 // We now we finished checking if there are still more character s. | |
4204 if (length < textLength) | |
4205 leadingSpacesChecked = true; | |
4206 } | |
4207 | |
4208 // If leading spaces have been checked, account now for leading punc tuation. | |
4209 if (!leadingPunctuationChecked && length < textLength) { | |
4210 while (length < textLength && isPunctuationForFirstLetter(text[l ength])) | |
4211 length++; | |
4212 | |
4213 // We now we finished checking if there are still more character s. | |
4214 if (length < textLength) | |
4215 leadingPunctuationChecked = true; | |
4216 } | |
4217 | |
4218 // Now account for the next character for first letter and the trail ing punctuation (if any). | |
4219 if (!firstLetterRenderersFound && length < textLength) { | |
4220 // Now spaces are allowed between leading punctuation and the le tter. | |
4221 if (isSpaceForFirstLetter(text[length])) | |
4222 break; | |
4223 | |
4224 firstLetterRenderersFound = true; | |
4225 length++; | |
4226 } | |
4227 | |
4228 // Keep looking allowed punctuation for the :first-letter. | |
4229 for (unsigned scanLength = length; scanLength < textLength; ++scanLe ngth) { | |
4230 UChar c = text[scanLength]; | |
4231 if (!isPunctuationForFirstLetter(c)) | |
4232 break; | |
4233 | |
4234 length = scanLength + 1; | |
4235 } | |
4236 | |
4237 // If we haven't found anything with the current renderer, it does n ot make sense to keep | |
4238 // checking more renderers, as they won't be part of the first-lette r pseudoelement anyway. | |
4239 if (!length) | |
4240 break; | |
4241 | |
4242 // Save the renderer so we can apply the right style to it later. | |
4243 renderers.append(currChild); | |
4244 | |
4245 // No need to keep looking if we already made a decision. | |
4246 if (length < textLength) | |
4247 break; | |
4248 | |
4249 // We need to look the next object traversing the tree in preorder a s if the current renderer | |
4250 // was a leaf node (which probably is anyway) but without leaving th e scope of the parent block. | |
4251 currChild = currChild->nextInPreOrderAfterChildren(firstLetterBlock) ; | |
4252 } else if (currChild->isListMarker()) { | |
4253 currChild = currChild->nextSibling(); | |
4254 } else if (currChild->isFloatingOrOutOfFlowPositioned()) { | |
4255 if (currChild->style()->styleType() == FIRST_LETTER) { | |
4256 currChild = currChild->firstChild(); | |
4257 if (currChild) { | |
4258 // If found a floating/out-of-flow element with the first_le tter | |
4259 // style already applied, it means it has been previously id entified | |
4260 // and so we should discard whatever we found so far and use that. | |
4261 firstLetterRenderersFound = true; | |
4262 renderers.append(currChild); | |
4263 } | |
4264 break; | |
4265 } | |
4266 currChild = currChild->nextSibling(); | |
4267 } else if (currChild->isReplaced() || currChild->isRenderButton() || cur rChild->isMenuList()) | |
4268 break; | |
4269 else if (currChild->style()->hasPseudoStyle(FIRST_LETTER) && currChild-> canHaveGeneratedChildren()) { | |
4270 // We found a lower-level node with first-letter, which supersedes t he higher-level style. | |
4271 firstLetterBlock = currChild; | |
4272 currChild = currChild->firstChild(); | |
4273 } else | |
4274 currChild = currChild->firstChild(); | |
4275 } | |
4276 | |
4277 if (!firstLetterRenderersFound) { | |
4278 // Empty the list of renderers if we did not find a correct set of them | |
4279 // to further generate new elements to apply the first-letter style over . | |
4280 renderers.clear(); | |
4281 } else if (!length) { | |
4282 // If we found renderers for the first-letter and length is zero it mean s that the last valid | |
4283 // renderer was added in the previous iteration of the loop, so we consi der its length instead. | |
4284 length = previousLength; | |
4285 } | |
4286 | |
4287 // Return the number of characters used for the first-letter pseudo element coming | |
4288 // from the last text renderer found, needed to create the last generated re nderer. | |
4289 return renderers.isEmpty() ? 0 : length; | |
4290 } | |
4291 | |
4187 void RenderBlock::updateFirstLetter() | 4292 void RenderBlock::updateFirstLetter() |
4188 { | 4293 { |
4189 if (!document().styleEngine()->usesFirstLetterRules()) | 4294 if (!document().styleEngine()->usesFirstLetterRules()) |
4190 return; | 4295 return; |
4296 | |
4191 // Don't recur | 4297 // Don't recur |
4192 if (style()->styleType() == FIRST_LETTER) | 4298 if (style()->styleType() == FIRST_LETTER) |
4193 return; | 4299 return; |
4194 | 4300 |
4195 // FIXME: We need to destroy the first-letter object if it is no longer the first child. Need to find | 4301 // FIXME: We need to destroy the first-letter object if it is no longer the first child. Need to find |
4196 // an efficient way to check for that situation though before implementing a nything. | 4302 // an efficient way to check for that situation though before implementing a nything. |
4197 RenderObject* firstLetterBlock = findFirstLetterBlock(this); | 4303 RenderObject* firstLetterBlock = findFirstLetterBlock(this); |
4198 if (!firstLetterBlock) | 4304 if (!firstLetterBlock) |
4199 return; | 4305 return; |
4200 | 4306 |
4201 // Drill into inlines looking for our first text child. | 4307 // Find the renderers to apply the first-letter style over. |
4202 RenderObject* currChild = firstLetterBlock->firstChild(); | 4308 Vector<RenderObject*> renderers; |
4203 unsigned length = 0; | 4309 unsigned lengthForLastRenderer = findTextRenderersForFirstLetterBlock(firstL etterBlock, renderers); |
4204 while (currChild) { | 4310 if (renderers.isEmpty()) |
4205 if (currChild->isText()) { | |
4206 // FIXME: If there is leading punctuation in a different RenderText than | |
4207 // the first letter, we'll not apply the correct style to it. | |
4208 length = firstLetterLength(toRenderText(currChild)->originalText()); | |
4209 if (length) | |
4210 break; | |
4211 currChild = currChild->nextSibling(); | |
4212 } else if (currChild->isListMarker()) { | |
4213 currChild = currChild->nextSibling(); | |
4214 } else if (currChild->isFloatingOrOutOfFlowPositioned()) { | |
4215 if (currChild->style()->styleType() == FIRST_LETTER) { | |
4216 currChild = currChild->firstChild(); | |
4217 break; | |
4218 } | |
4219 currChild = currChild->nextSibling(); | |
4220 } else if (currChild->isReplaced() || currChild->isRenderButton() || cur rChild->isMenuList()) | |
4221 break; | |
4222 else if (currChild->style()->hasPseudoStyle(FIRST_LETTER) && currChild-> canHaveGeneratedChildren()) { | |
4223 // We found a lower-level node with first-letter, which supersedes t he higher-level style | |
4224 firstLetterBlock = currChild; | |
4225 currChild = currChild->firstChild(); | |
4226 } else | |
4227 currChild = currChild->firstChild(); | |
4228 } | |
4229 | |
4230 if (!currChild) | |
4231 return; | 4311 return; |
4232 | 4312 |
4233 // If the child already has style, then it has already been created, so we j ust want | 4313 // Create the new renderers for the first-letter pseudo elements. |
4234 // to update it. | 4314 for (Vector<RenderObject*>::const_iterator it = renderers.begin(); it != ren derers.end(); ++it) { |
4235 if (currChild->parent()->style()->styleType() == FIRST_LETTER) { | 4315 RenderObject* currentRenderer = *it; |
4236 updateFirstLetterStyle(firstLetterBlock, currChild); | 4316 ASSERT(currentRenderer->isText()); |
4237 return; | 4317 |
4318 // If the child already has style, then it has already been created, so we just want | |
4319 // to update it. | |
4320 if (currentRenderer->parent()->style()->styleType() == FIRST_LETTER) { | |
4321 updateFirstLetterStyle(firstLetterBlock, currentRenderer); | |
4322 continue; | |
4323 } | |
4324 | |
4325 // FIXME: This black-list of disallowed RenderText subclasses is fragile . | |
4326 // Should counter be on this list? What about RenderTextFragment? | |
4327 RenderText* textRenderer = toRenderText(currentRenderer); | |
4328 if (!currentRenderer->isText() || currentRenderer->isBR() || textRendere r->isWordBreak()) | |
4329 continue; | |
4330 | |
4331 // Our layout state is not valid for the repaints we are going to trigge r by | |
4332 // adding and removing children of firstLetterContainer. | |
4333 LayoutStateDisabler layoutStateDisabler(*this); | |
4334 | |
4335 unsigned lengthForRenderer = 0; | |
4336 if (currentRenderer == renderers.last()) | |
4337 lengthForRenderer = lengthForLastRenderer; | |
4338 else | |
4339 lengthForRenderer = getRendererTextForFirstLetter(currentRenderer).l ength(); | |
4340 | |
4341 if (lengthForRenderer) | |
4342 createFirstLetterRenderer(firstLetterBlock, currentRenderer, lengthF orRenderer); | |
4238 } | 4343 } |
4239 | |
4240 // FIXME: This black-list of disallowed RenderText subclasses is fragile. | |
4241 // Should counter be on this list? What about RenderTextFragment? | |
4242 if (!currChild->isText() || currChild->isBR() || toRenderText(currChild)->is WordBreak()) | |
4243 return; | |
4244 | |
4245 // Our layout state is not valid for the repaints we are going to trigger by | |
4246 // adding and removing children of firstLetterContainer. | |
4247 LayoutStateDisabler layoutStateDisabler(*this); | |
4248 | |
4249 createFirstLetterRenderer(firstLetterBlock, currChild, length); | |
4250 } | 4344 } |
4251 | 4345 |
4252 // Helper methods for obtaining the last line, computing line counts and heights for line counts | 4346 // Helper methods for obtaining the last line, computing line counts and heights for line counts |
4253 // (crawling into blocks). | 4347 // (crawling into blocks). |
4254 static bool shouldCheckLines(RenderObject* obj) | 4348 static bool shouldCheckLines(RenderObject* obj) |
4255 { | 4349 { |
4256 return !obj->isFloatingOrOutOfFlowPositioned() | 4350 return !obj->isFloatingOrOutOfFlowPositioned() |
4257 && obj->isRenderBlock() && obj->style()->height().isAuto() | 4351 && obj->isRenderBlock() && obj->style()->height().isAuto() |
4258 && (!obj->isDeprecatedFlexibleBox() || obj->style()->boxOrient() == VERT ICAL); | 4352 && (!obj->isDeprecatedFlexibleBox() || obj->style()->boxOrient() == VERT ICAL); |
4259 } | 4353 } |
(...skipping 765 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
5025 void RenderBlock::showLineTreeAndMark(const InlineBox* markedBox1, const char* m arkedLabel1, const InlineBox* markedBox2, const char* markedLabel2, const Render Object* obj) const | 5119 void RenderBlock::showLineTreeAndMark(const InlineBox* markedBox1, const char* m arkedLabel1, const InlineBox* markedBox2, const char* markedLabel2, const Render Object* obj) const |
5026 { | 5120 { |
5027 showRenderObject(); | 5121 showRenderObject(); |
5028 for (const RootInlineBox* root = firstRootBox(); root; root = root->nextRoot Box()) | 5122 for (const RootInlineBox* root = firstRootBox(); root; root = root->nextRoot Box()) |
5029 root->showLineTreeAndMark(markedBox1, markedLabel1, markedBox2, markedLa bel2, obj, 1); | 5123 root->showLineTreeAndMark(markedBox1, markedLabel1, markedBox2, markedLa bel2, obj, 1); |
5030 } | 5124 } |
5031 | 5125 |
5032 #endif | 5126 #endif |
5033 | 5127 |
5034 } // namespace WebCore | 5128 } // namespace WebCore |
OLD | NEW |