| 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 * | 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 |
| 11 * version 2 of the License, or (at your option) any later version. | 11 * version 2 of the License, or (at your option) any later version. |
| 12 * | 12 * |
| 13 * This library is distributed in the hope that it will be useful, | 13 * This library is distributed in the hope that it will be useful, |
| 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of | 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 16 * Library General Public License for more details. | 16 * Library General Public License for more details. |
| 17 * | 17 * |
| 18 * You should have received a copy of the GNU Library General Public License | 18 * You should have received a copy of the GNU Library General Public License |
| 19 * along with this library; see the file COPYING.LIB. If not, write to | 19 * along with this library; see the file COPYING.LIB. If not, write to |
| 20 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | 20 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
| 21 * Boston, MA 02110-1301, USA. | 21 * Boston, MA 02110-1301, USA. |
| 22 */ | 22 */ |
| 23 | 23 |
| 24 #include "config.h" | 24 #include "config.h" |
| 25 #include "core/dom/FirstLetterPseudoElement.h" | 25 #include "core/dom/FirstLetterPseudoElement.h" |
| 26 | 26 |
| 27 #include "core/dom/Element.h" | 27 #include "core/dom/Element.h" |
| 28 #include "core/rendering/RenderObject.h" | 28 #include "core/layout/LayoutObject.h" |
| 29 #include "core/rendering/RenderObjectInlines.h" | 29 #include "core/layout/LayoutObjectInlines.h" |
| 30 #include "core/rendering/RenderText.h" | 30 #include "core/rendering/RenderText.h" |
| 31 #include "core/rendering/RenderTextFragment.h" | 31 #include "core/rendering/RenderTextFragment.h" |
| 32 #include "wtf/TemporaryChange.h" | 32 #include "wtf/TemporaryChange.h" |
| 33 #include "wtf/text/WTFString.h" | 33 #include "wtf/text/WTFString.h" |
| 34 #include "wtf/unicode/icu/UnicodeIcu.h" | 34 #include "wtf/unicode/icu/UnicodeIcu.h" |
| 35 | 35 |
| 36 namespace blink { | 36 namespace blink { |
| 37 | 37 |
| 38 using namespace WTF; | 38 using namespace WTF; |
| 39 using namespace Unicode; | 39 using namespace Unicode; |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 82 for (; length < textLength; ++length) { | 82 for (; length < textLength; ++length) { |
| 83 UChar c = text[length]; | 83 UChar c = text[length]; |
| 84 if (!isPunctuationForFirstLetter(c)) | 84 if (!isPunctuationForFirstLetter(c)) |
| 85 break; | 85 break; |
| 86 } | 86 } |
| 87 return length; | 87 return length; |
| 88 } | 88 } |
| 89 | 89 |
| 90 // Once we see any of these renderers we can stop looking for first-letter as | 90 // Once we see any of these renderers we can stop looking for first-letter as |
| 91 // they signal the end of the first line of text. | 91 // they signal the end of the first line of text. |
| 92 static bool isInvalidFirstLetterRenderer(const RenderObject* obj) | 92 static bool isInvalidFirstLetterRenderer(const LayoutObject* obj) |
| 93 { | 93 { |
| 94 return (obj->isBR() || (obj->isText() && toRenderText(obj)->isWordBreak())); | 94 return (obj->isBR() || (obj->isText() && toRenderText(obj)->isWordBreak())); |
| 95 } | 95 } |
| 96 | 96 |
| 97 RenderObject* FirstLetterPseudoElement::firstLetterTextRenderer(const Element& e
lement) | 97 LayoutObject* FirstLetterPseudoElement::firstLetterTextRenderer(const Element& e
lement) |
| 98 { | 98 { |
| 99 RenderObject* parentRenderer = 0; | 99 LayoutObject* parentRenderer = 0; |
| 100 | 100 |
| 101 // If we are looking at a first letter element then we need to find the | 101 // If we are looking at a first letter element then we need to find the |
| 102 // first letter text renderer from the parent node, and not ourselves. | 102 // first letter text renderer from the parent node, and not ourselves. |
| 103 if (element.isFirstLetterPseudoElement()) | 103 if (element.isFirstLetterPseudoElement()) |
| 104 parentRenderer = element.parentOrShadowHostElement()->renderer(); | 104 parentRenderer = element.parentOrShadowHostElement()->renderer(); |
| 105 else | 105 else |
| 106 parentRenderer = element.renderer(); | 106 parentRenderer = element.renderer(); |
| 107 | 107 |
| 108 if (!parentRenderer | 108 if (!parentRenderer |
| 109 || !parentRenderer->style()->hasPseudoStyle(FIRST_LETTER) | 109 || !parentRenderer->style()->hasPseudoStyle(FIRST_LETTER) |
| 110 || !parentRenderer->canHaveGeneratedChildren() | 110 || !parentRenderer->canHaveGeneratedChildren() |
| 111 || !(parentRenderer->isRenderBlockFlow() || parentRenderer->isRenderButt
on())) | 111 || !(parentRenderer->isRenderBlockFlow() || parentRenderer->isRenderButt
on())) |
| 112 return nullptr; | 112 return nullptr; |
| 113 | 113 |
| 114 // Drill down into our children and look for our first text child. | 114 // Drill down into our children and look for our first text child. |
| 115 RenderObject* firstLetterTextRenderer = parentRenderer->slowFirstChild(); | 115 LayoutObject* firstLetterTextRenderer = parentRenderer->slowFirstChild(); |
| 116 while (firstLetterTextRenderer) { | 116 while (firstLetterTextRenderer) { |
| 117 // This can be called when the first letter renderer is already in the t
ree. We do not | 117 // This can be called when the first letter renderer is already in the t
ree. We do not |
| 118 // want to consider that renderer for our text renderer so we go to the
sibling (which is | 118 // want to consider that renderer for our text renderer so we go to the
sibling (which is |
| 119 // the RenderTextFragment for the remaining text). | 119 // the RenderTextFragment for the remaining text). |
| 120 if (firstLetterTextRenderer->style() && firstLetterTextRenderer->style()
->styleType() == FIRST_LETTER) { | 120 if (firstLetterTextRenderer->style() && firstLetterTextRenderer->style()
->styleType() == FIRST_LETTER) { |
| 121 firstLetterTextRenderer = firstLetterTextRenderer->nextSibling(); | 121 firstLetterTextRenderer = firstLetterTextRenderer->nextSibling(); |
| 122 } else if (firstLetterTextRenderer->isText()) { | 122 } else if (firstLetterTextRenderer->isText()) { |
| 123 // FIXME: If there is leading punctuation in a different RenderText
than | 123 // FIXME: If there is leading punctuation in a different RenderText
than |
| 124 // the first letter, we'll not apply the correct style to it. | 124 // the first letter, we'll not apply the correct style to it. |
| 125 RefPtr<StringImpl> str = toRenderText(firstLetterTextRenderer)->isTe
xtFragment() ? | 125 RefPtr<StringImpl> str = toRenderText(firstLetterTextRenderer)->isTe
xtFragment() ? |
| (...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 217 m_remainingTextRenderer->setTextFragment(textNode->dataImpl(), 0, te
xtNode->dataImpl()->length()); | 217 m_remainingTextRenderer->setTextFragment(textNode->dataImpl(), 0, te
xtNode->dataImpl()->length()); |
| 218 } | 218 } |
| 219 m_remainingTextRenderer->setFirstLetterPseudoElement(nullptr); | 219 m_remainingTextRenderer->setFirstLetterPseudoElement(nullptr); |
| 220 m_remainingTextRenderer->setIsRemainingTextRenderer(false); | 220 m_remainingTextRenderer->setIsRemainingTextRenderer(false); |
| 221 } | 221 } |
| 222 m_remainingTextRenderer = nullptr; | 222 m_remainingTextRenderer = nullptr; |
| 223 | 223 |
| 224 PseudoElement::detach(context); | 224 PseudoElement::detach(context); |
| 225 } | 225 } |
| 226 | 226 |
| 227 RenderStyle* FirstLetterPseudoElement::styleForFirstLetter(RenderObject* rendere
rContainer) | 227 RenderStyle* FirstLetterPseudoElement::styleForFirstLetter(LayoutObject* rendere
rContainer) |
| 228 { | 228 { |
| 229 ASSERT(rendererContainer); | 229 ASSERT(rendererContainer); |
| 230 | 230 |
| 231 RenderObject* styleContainer = parentOrShadowHostElement()->renderer(); | 231 LayoutObject* styleContainer = parentOrShadowHostElement()->renderer(); |
| 232 ASSERT(styleContainer); | 232 ASSERT(styleContainer); |
| 233 | 233 |
| 234 // We always force the pseudo style to recompute as the first-letter style | 234 // We always force the pseudo style to recompute as the first-letter style |
| 235 // computed by the style container may not have taken the renderers styles | 235 // computed by the style container may not have taken the renderers styles |
| 236 // into account. | 236 // into account. |
| 237 styleContainer->style()->removeCachedPseudoStyle(FIRST_LETTER); | 237 styleContainer->style()->removeCachedPseudoStyle(FIRST_LETTER); |
| 238 | 238 |
| 239 RenderStyle* pseudoStyle = styleContainer->getCachedPseudoStyle(FIRST_LETTER
, rendererContainer->firstLineStyle()); | 239 RenderStyle* pseudoStyle = styleContainer->getCachedPseudoStyle(FIRST_LETTER
, rendererContainer->firstLineStyle()); |
| 240 ASSERT(pseudoStyle); | 240 ASSERT(pseudoStyle); |
| 241 | 241 |
| 242 return pseudoStyle; | 242 return pseudoStyle; |
| 243 } | 243 } |
| 244 | 244 |
| 245 void FirstLetterPseudoElement::attachFirstLetterTextRenderers() | 245 void FirstLetterPseudoElement::attachFirstLetterTextRenderers() |
| 246 { | 246 { |
| 247 RenderObject* nextRenderer = FirstLetterPseudoElement::firstLetterTextRender
er(*this); | 247 LayoutObject* nextRenderer = FirstLetterPseudoElement::firstLetterTextRender
er(*this); |
| 248 ASSERT(nextRenderer); | 248 ASSERT(nextRenderer); |
| 249 ASSERT(nextRenderer->isText()); | 249 ASSERT(nextRenderer->isText()); |
| 250 | 250 |
| 251 // The original string is going to be either a generated content string or a
DOM node's | 251 // The original string is going to be either a generated content string or a
DOM node's |
| 252 // string. We want the original string before it got transformed in case fir
st-letter has | 252 // string. We want the original string before it got transformed in case fir
st-letter has |
| 253 // no text-transform or a different text-transform applied to it. | 253 // no text-transform or a different text-transform applied to it. |
| 254 String oldText = toRenderText(nextRenderer)->isTextFragment() ? toRenderText
Fragment(nextRenderer)->completeText() : toRenderText(nextRenderer)->originalTex
t(); | 254 String oldText = toRenderText(nextRenderer)->isTextFragment() ? toRenderText
Fragment(nextRenderer)->completeText() : toRenderText(nextRenderer)->originalTex
t(); |
| 255 ASSERT(oldText.impl()); | 255 ASSERT(oldText.impl()); |
| 256 | 256 |
| 257 RenderStyle* pseudoStyle = styleForFirstLetter(nextRenderer->parent()); | 257 RenderStyle* pseudoStyle = styleForFirstLetter(nextRenderer->parent()); |
| 258 renderer()->setStyle(pseudoStyle); | 258 renderer()->setStyle(pseudoStyle); |
| 259 | 259 |
| 260 // FIXME: This would already have been calculated in firstLetterRenderer. Ca
n we pass the length through? | 260 // FIXME: This would already have been calculated in firstLetterRenderer. Ca
n we pass the length through? |
| 261 unsigned length = FirstLetterPseudoElement::firstLetterLength(oldText); | 261 unsigned length = FirstLetterPseudoElement::firstLetterLength(oldText); |
| 262 | 262 |
| 263 // Construct a text fragment for the text after the first letter. | 263 // Construct a text fragment for the text after the first letter. |
| 264 // This text fragment might be empty. | 264 // This text fragment might be empty. |
| 265 RenderTextFragment* remainingText = | 265 RenderTextFragment* remainingText = |
| 266 new RenderTextFragment(nextRenderer->node() ? nextRenderer->node() : &ne
xtRenderer->document(), oldText.impl(), length, oldText.length() - length); | 266 new RenderTextFragment(nextRenderer->node() ? nextRenderer->node() : &ne
xtRenderer->document(), oldText.impl(), length, oldText.length() - length); |
| 267 remainingText->setFirstLetterPseudoElement(this); | 267 remainingText->setFirstLetterPseudoElement(this); |
| 268 remainingText->setIsRemainingTextRenderer(true); | 268 remainingText->setIsRemainingTextRenderer(true); |
| 269 remainingText->setStyle(nextRenderer->style()); | 269 remainingText->setStyle(nextRenderer->style()); |
| 270 | 270 |
| 271 if (remainingText->node()) | 271 if (remainingText->node()) |
| 272 remainingText->node()->setRenderer(remainingText); | 272 remainingText->node()->setRenderer(remainingText); |
| 273 | 273 |
| 274 m_remainingTextRenderer = remainingText; | 274 m_remainingTextRenderer = remainingText; |
| 275 | 275 |
| 276 RenderObject* nextSibling = renderer()->nextSibling(); | 276 LayoutObject* nextSibling = renderer()->nextSibling(); |
| 277 renderer()->parent()->addChild(remainingText, nextSibling); | 277 renderer()->parent()->addChild(remainingText, nextSibling); |
| 278 | 278 |
| 279 // Construct text fragment for the first letter. | 279 // Construct text fragment for the first letter. |
| 280 RenderTextFragment* letter = new RenderTextFragment(&nextRenderer->document(
), oldText.impl(), 0, length); | 280 RenderTextFragment* letter = new RenderTextFragment(&nextRenderer->document(
), oldText.impl(), 0, length); |
| 281 letter->setFirstLetterPseudoElement(this); | 281 letter->setFirstLetterPseudoElement(this); |
| 282 letter->setStyle(pseudoStyle); | 282 letter->setStyle(pseudoStyle); |
| 283 renderer()->addChild(letter); | 283 renderer()->addChild(letter); |
| 284 | 284 |
| 285 nextRenderer->destroy(); | 285 nextRenderer->destroy(); |
| 286 } | 286 } |
| 287 | 287 |
| 288 void FirstLetterPseudoElement::didRecalcStyle(StyleRecalcChange) | 288 void FirstLetterPseudoElement::didRecalcStyle(StyleRecalcChange) |
| 289 { | 289 { |
| 290 if (!renderer()) | 290 if (!renderer()) |
| 291 return; | 291 return; |
| 292 | 292 |
| 293 // The renderers inside pseudo elements are anonymous so they don't get noti
fied of recalcStyle and must have | 293 // The renderers inside pseudo elements are anonymous so they don't get noti
fied of recalcStyle and must have |
| 294 // the style propagated downward manually similar to RenderObject::propagate
StyleToAnonymousChildren. | 294 // the style propagated downward manually similar to LayoutObject::propagate
StyleToAnonymousChildren. |
| 295 RenderObject* renderer = this->renderer(); | 295 LayoutObject* renderer = this->renderer(); |
| 296 for (RenderObject* child = renderer->nextInPreOrder(renderer); child; child
= child->nextInPreOrder(renderer)) { | 296 for (LayoutObject* child = renderer->nextInPreOrder(renderer); child; child
= child->nextInPreOrder(renderer)) { |
| 297 // We need to re-calculate the correct style for the first letter elemen
t | 297 // We need to re-calculate the correct style for the first letter elemen
t |
| 298 // and then apply that to the container and the text fragment inside. | 298 // and then apply that to the container and the text fragment inside. |
| 299 if (child->style()->styleType() == FIRST_LETTER && m_remainingTextRender
er) { | 299 if (child->style()->styleType() == FIRST_LETTER && m_remainingTextRender
er) { |
| 300 if (RenderStyle* pseudoStyle = styleForFirstLetter(m_remainingTextRe
nderer->parent())) | 300 if (RenderStyle* pseudoStyle = styleForFirstLetter(m_remainingTextRe
nderer->parent())) |
| 301 child->setPseudoStyle(pseudoStyle); | 301 child->setPseudoStyle(pseudoStyle); |
| 302 continue; | 302 continue; |
| 303 } | 303 } |
| 304 | 304 |
| 305 // We only manage the style for the generated content items. | 305 // We only manage the style for the generated content items. |
| 306 if (!child->isText() && !child->isQuote() && !child->isImage()) | 306 if (!child->isText() && !child->isQuote() && !child->isImage()) |
| 307 continue; | 307 continue; |
| 308 | 308 |
| 309 child->setPseudoStyle(renderer->style()); | 309 child->setPseudoStyle(renderer->style()); |
| 310 } | 310 } |
| 311 } | 311 } |
| 312 | 312 |
| 313 } // namespace blink | 313 } // namespace blink |
| OLD | NEW |