Chromium Code Reviews| 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) 2001 Peter Kelly (pmk@post.com) | 4 * (C) 2001 Peter Kelly (pmk@post.com) |
| 5 * (C) 2001 Dirk Mueller (mueller@kde.org) | 5 * (C) 2001 Dirk Mueller (mueller@kde.org) |
| 6 * (C) 2007 David Smith (catfish.man@gmail.com) | 6 * (C) 2007 David Smith (catfish.man@gmail.com) |
| 7 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2012, 2013 Apple Inc. All rights reserved. | 7 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2012, 2013 Apple Inc. All rights reserved. |
| 8 * (C) 2007 Eric Seidel (eric@webkit.org) | 8 * (C) 2007 Eric Seidel (eric@webkit.org) |
| 9 * | 9 * |
| 10 * This library is free software; you can redistribute it and/or | 10 * This library is free software; you can redistribute it and/or |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 96 #include "core/html/HTMLTableRowsCollection.h" | 96 #include "core/html/HTMLTableRowsCollection.h" |
| 97 #include "core/html/HTMLTemplateElement.h" | 97 #include "core/html/HTMLTemplateElement.h" |
| 98 #include "core/html/parser/HTMLParserIdioms.h" | 98 #include "core/html/parser/HTMLParserIdioms.h" |
| 99 #include "core/inspector/InspectorInstrumentation.h" | 99 #include "core/inspector/InspectorInstrumentation.h" |
| 100 #include "core/page/Chrome.h" | 100 #include "core/page/Chrome.h" |
| 101 #include "core/page/ChromeClient.h" | 101 #include "core/page/ChromeClient.h" |
| 102 #include "core/page/FocusController.h" | 102 #include "core/page/FocusController.h" |
| 103 #include "core/page/Page.h" | 103 #include "core/page/Page.h" |
| 104 #include "core/page/PointerLockController.h" | 104 #include "core/page/PointerLockController.h" |
| 105 #include "core/rendering/RenderLayer.h" | 105 #include "core/rendering/RenderLayer.h" |
| 106 #include "core/rendering/RenderTextFragment.h" | |
| 106 #include "core/rendering/RenderView.h" | 107 #include "core/rendering/RenderView.h" |
| 107 #include "core/rendering/compositing/RenderLayerCompositor.h" | 108 #include "core/rendering/compositing/RenderLayerCompositor.h" |
| 108 #include "core/svg/SVGDocumentExtensions.h" | 109 #include "core/svg/SVGDocumentExtensions.h" |
| 109 #include "core/svg/SVGElement.h" | 110 #include "core/svg/SVGElement.h" |
| 110 #include "platform/EventDispatchForbiddenScope.h" | 111 #include "platform/EventDispatchForbiddenScope.h" |
| 111 #include "platform/RuntimeEnabledFeatures.h" | 112 #include "platform/RuntimeEnabledFeatures.h" |
| 112 #include "platform/UserGestureIndicator.h" | 113 #include "platform/UserGestureIndicator.h" |
| 113 #include "platform/scroll/ScrollableArea.h" | 114 #include "platform/scroll/ScrollableArea.h" |
| 114 #include "wtf/BitVector.h" | 115 #include "wtf/BitVector.h" |
| 115 #include "wtf/HashFunctions.h" | 116 #include "wtf/HashFunctions.h" |
| 116 #include "wtf/text/CString.h" | 117 #include "wtf/text/CString.h" |
| 117 #include "wtf/text/StringBuilder.h" | 118 #include "wtf/text/StringBuilder.h" |
| 118 #include "wtf/text/TextPosition.h" | 119 #include "wtf/text/TextPosition.h" |
| 120 #include "wtf/unicode/icu/UnicodeIcu.h" | |
| 119 | 121 |
| 120 namespace blink { | 122 namespace blink { |
| 121 | 123 |
| 122 using namespace HTMLNames; | 124 using namespace HTMLNames; |
| 123 using namespace XMLNames; | 125 using namespace XMLNames; |
| 124 | 126 |
| 127 using namespace WTF; | |
| 128 using namespace Unicode; | |
| 129 | |
| 125 typedef WillBeHeapVector<RefPtrWillBeMember<Attr> > AttrNodeList; | 130 typedef WillBeHeapVector<RefPtrWillBeMember<Attr> > AttrNodeList; |
| 126 | 131 |
| 127 static Attr* findAttrNodeInList(const AttrNodeList& attrNodeList, const Qualifie dName& name) | 132 static Attr* findAttrNodeInList(const AttrNodeList& attrNodeList, const Qualifie dName& name) |
| 128 { | 133 { |
| 129 AttrNodeList::const_iterator end = attrNodeList.end(); | 134 AttrNodeList::const_iterator end = attrNodeList.end(); |
| 130 for (AttrNodeList::const_iterator it = attrNodeList.begin(); it != end; ++it ) { | 135 for (AttrNodeList::const_iterator it = attrNodeList.begin(); it != end; ++it ) { |
| 131 if ((*it)->qualifiedName() == name) | 136 if ((*it)->qualifiedName() == name) |
| 132 return it->get(); | 137 return it->get(); |
| 133 } | 138 } |
| 134 return 0; | 139 return 0; |
| (...skipping 1204 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1339 | 1344 |
| 1340 // When a shadow root exists, it does the work of attaching the children. | 1345 // When a shadow root exists, it does the work of attaching the children. |
| 1341 if (ElementShadow* shadow = this->shadow()) | 1346 if (ElementShadow* shadow = this->shadow()) |
| 1342 shadow->attach(context); | 1347 shadow->attach(context); |
| 1343 | 1348 |
| 1344 ContainerNode::attach(context); | 1349 ContainerNode::attach(context); |
| 1345 | 1350 |
| 1346 createPseudoElementIfNeeded(AFTER); | 1351 createPseudoElementIfNeeded(AFTER); |
| 1347 createPseudoElementIfNeeded(BACKDROP); | 1352 createPseudoElementIfNeeded(BACKDROP); |
| 1348 | 1353 |
| 1354 // We create the first-letter element after the :before, :after and | |
| 1355 // children are attached because the first letter text could come | |
| 1356 // from any of them. | |
| 1357 createPseudoElementIfNeeded(FIRST_LETTER); | |
| 1358 | |
| 1349 if (hasRareData() && !renderer()) { | 1359 if (hasRareData() && !renderer()) { |
| 1350 if (ActiveAnimations* activeAnimations = elementRareData()->activeAnimat ions()) { | 1360 if (ActiveAnimations* activeAnimations = elementRareData()->activeAnimat ions()) { |
| 1351 activeAnimations->cssAnimations().cancel(); | 1361 activeAnimations->cssAnimations().cancel(); |
| 1352 activeAnimations->setAnimationStyleChange(false); | 1362 activeAnimations->setAnimationStyleChange(false); |
| 1353 } | 1363 } |
| 1354 } | 1364 } |
| 1355 } | 1365 } |
| 1356 | 1366 |
| 1357 void Element::detach(const AttachContext& context) | 1367 void Element::detach(const AttachContext& context) |
| 1358 { | 1368 { |
| (...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1498 for (ShadowRoot* root = youngestShadowRoot(); root; root = root->old erShadowRoot()) { | 1508 for (ShadowRoot* root = youngestShadowRoot(); root; root = root->old erShadowRoot()) { |
| 1499 if (root->shouldCallRecalcStyle(change)) | 1509 if (root->shouldCallRecalcStyle(change)) |
| 1500 root->recalcStyle(change); | 1510 root->recalcStyle(change); |
| 1501 } | 1511 } |
| 1502 recalcChildStyle(change); | 1512 recalcChildStyle(change); |
| 1503 } | 1513 } |
| 1504 | 1514 |
| 1505 updatePseudoElement(AFTER, change); | 1515 updatePseudoElement(AFTER, change); |
| 1506 updatePseudoElement(BACKDROP, change); | 1516 updatePseudoElement(BACKDROP, change); |
| 1507 | 1517 |
| 1518 // If our children have changed then we need to force the first-letter | |
| 1519 // checks as we don't know if they effected the first letter or not. | |
| 1520 // This can be seen when a child transitions from floating to | |
| 1521 // non-floating we have to take it into account for the first letter. | |
| 1522 updatePseudoElement(FIRST_LETTER, childNeedsStyleRecalc() ? Force : chan ge); | |
| 1523 | |
| 1508 clearChildNeedsStyleRecalc(); | 1524 clearChildNeedsStyleRecalc(); |
| 1509 } | 1525 } |
| 1510 | 1526 |
| 1511 if (hasCustomStyleCallbacks()) | 1527 if (hasCustomStyleCallbacks()) |
| 1512 didRecalcStyle(change); | 1528 didRecalcStyle(change); |
| 1513 | 1529 |
| 1514 if (change == Reattach) | 1530 if (change == Reattach) |
| 1515 reattachWhitespaceSiblings(nextTextSibling); | 1531 reattachWhitespaceSiblings(nextTextSibling); |
| 1516 } | 1532 } |
| 1517 | 1533 |
| (...skipping 212 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1730 return; | 1746 return; |
| 1731 | 1747 |
| 1732 if (!style || (styleAffectedByEmpty() && (!style->emptyState() || hasChildre n()))) | 1748 if (!style || (styleAffectedByEmpty() && (!style->emptyState() || hasChildre n()))) |
| 1733 document().styleResolver()->ensureUpdatedRuleFeatureSet().scheduleStyleI nvalidationForPseudoChange(CSSSelector::PseudoEmpty, *this); | 1749 document().styleResolver()->ensureUpdatedRuleFeatureSet().scheduleStyleI nvalidationForPseudoChange(CSSSelector::PseudoEmpty, *this); |
| 1734 } | 1750 } |
| 1735 | 1751 |
| 1736 void Element::childrenChanged(const ChildrenChange& change) | 1752 void Element::childrenChanged(const ChildrenChange& change) |
| 1737 { | 1753 { |
| 1738 ContainerNode::childrenChanged(change); | 1754 ContainerNode::childrenChanged(change); |
| 1739 | 1755 |
| 1756 if (change.isChildRemoval() && pseudoElement(FIRST_LETTER)) | |
| 1757 clearFirstLetterPseudoElement(); | |
|
esprehn
2014/09/30 09:00:30
Destroying it on every child mutation doesn't seem
dsinclair
2014/09/30 21:46:33
Removed. Re-ran the layout tests with this removed
| |
| 1758 | |
| 1740 checkForEmptyStyleChange(); | 1759 checkForEmptyStyleChange(); |
| 1741 if (!change.byParser && change.isChildElementChange()) | 1760 if (!change.byParser && change.isChildElementChange()) |
| 1742 checkForSiblingStyleChanges(change.type == ElementRemoved ? SiblingEleme ntRemoved : SiblingElementInserted, change.siblingBeforeChange, change.siblingAf terChange); | 1761 checkForSiblingStyleChanges(change.type == ElementRemoved ? SiblingEleme ntRemoved : SiblingElementInserted, change.siblingBeforeChange, change.siblingAf terChange); |
| 1743 | 1762 |
| 1744 if (ElementShadow* shadow = this->shadow()) | 1763 if (ElementShadow* shadow = this->shadow()) |
| 1745 shadow->setNeedsDistributionRecalc(); | 1764 shadow->setNeedsDistributionRecalc(); |
| 1746 } | 1765 } |
| 1747 | 1766 |
| 1748 void Element::finishParsingChildren() | 1767 void Element::finishParsingChildren() |
| 1749 { | 1768 { |
| (...skipping 729 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2479 // attributes while we are iterating. | 2498 // attributes while we are iterating. |
| 2480 WillBeHeapVector<RefPtrWillBeMember<Attr> > attrNodesCopy(*attrNodes); | 2499 WillBeHeapVector<RefPtrWillBeMember<Attr> > attrNodesCopy(*attrNodes); |
| 2481 for (size_t i = 0; i < attrNodesCopy.size(); ++i) | 2500 for (size_t i = 0; i < attrNodesCopy.size(); ++i) |
| 2482 attrNodesCopy[i]->normalize(); | 2501 attrNodesCopy[i]->normalize(); |
| 2483 } | 2502 } |
| 2484 | 2503 |
| 2485 void Element::updatePseudoElement(PseudoId pseudoId, StyleRecalcChange change) | 2504 void Element::updatePseudoElement(PseudoId pseudoId, StyleRecalcChange change) |
| 2486 { | 2505 { |
| 2487 ASSERT(!needsStyleRecalc()); | 2506 ASSERT(!needsStyleRecalc()); |
| 2488 PseudoElement* element = pseudoElement(pseudoId); | 2507 PseudoElement* element = pseudoElement(pseudoId); |
| 2489 if (element && (change == UpdatePseudoElements || element->shouldCallRecalcS tyle(change))) { | 2508 |
| 2509 // We have a first-letter pseudoElement, but we no longer should have one. | |
| 2510 // This can happen if we change to a float, for example. We need to cleanup the | |
| 2511 // first-letter pseudoElement and then fix the text the original remaining | |
| 2512 // text renderer. | |
| 2513 if (pseudoId == FIRST_LETTER && element && !element->firstLetterTextRenderer ()) { | |
|
esprehn
2014/09/30 09:00:30
Why can't we handle this in the code below?
dsinclair
2014/09/30 21:46:33
Done.
Moved it into the if (change >= UpdatePseud
| |
| 2514 elementRareData()->setPseudoElement(pseudoId, nullptr); | |
| 2515 | |
| 2516 // For first-letter we need to force the style recalc here. The first letter | |
| 2517 // node's renderer needs to be forced to get a new style. This can be seen | |
| 2518 // in fast/css/first-letter-nested.html when we change the font size of | |
| 2519 // test_span_2. | |
|
esprehn
2014/09/30 09:00:30
Why? This comment explains what you're doing but n
dsinclair
2014/09/30 21:46:33
The caller is now doing a Force if the children ha
| |
| 2520 } else if (element && (change == UpdatePseudoElements || element->shouldCall RecalcStyle(change) | |
| 2521 || element->isFirstLetterPseudoElement())) { | |
| 2522 | |
| 2523 // If we're updating first letter, and the current first letter renderer | |
| 2524 // is not the same as the one we're currently using we need to re-create | |
| 2525 // the first letter renderer. | |
| 2526 if (pseudoId == FIRST_LETTER && element->firstLetterTextRenderer() != el ement->remainingTextRenderer()) { | |
|
esprehn
2014/09/30 09:00:30
firstLetterTextRenderer() doesn't seem like someth
dsinclair
2014/09/30 21:46:33
Done.
| |
| 2527 elementRareData()->setPseudoElement(pseudoId, nullptr); | |
| 2528 createPseudoElementIfNeeded(pseudoId); | |
| 2529 return; | |
| 2530 } | |
| 2490 | 2531 |
| 2491 // Need to clear the cached style if the PseudoElement wants a recalc so it | 2532 // Need to clear the cached style if the PseudoElement wants a recalc so it |
| 2492 // computes a new style. | 2533 // computes a new style. |
| 2493 if (element->needsStyleRecalc()) | 2534 if (element->needsStyleRecalc()) |
| 2494 renderer()->style()->removeCachedPseudoStyle(pseudoId); | 2535 renderer()->style()->removeCachedPseudoStyle(pseudoId); |
| 2495 | 2536 |
| 2496 // PseudoElement styles hang off their parent element's style so if we n eeded | 2537 // PseudoElement styles hang off their parent element's style so if we n eeded |
| 2497 // a style recalc we should Force one on the pseudo. | 2538 // a style recalc we should Force one on the pseudo. |
| 2498 // FIXME: We should figure out the right text sibling to pass. | 2539 // FIXME: We should figure out the right text sibling to pass. |
| 2499 element->recalcStyle(change == UpdatePseudoElements ? Force : change); | 2540 element->recalcStyle(change == UpdatePseudoElements ? Force : change); |
| 2500 | 2541 |
| 2501 // Wait until our parent is not displayed or pseudoElementRendererIsNeed ed | 2542 // Wait until our parent is not displayed or pseudoElementRendererIsNeed ed |
| 2502 // is false, otherwise we could continously create and destroy PseudoEle ments | 2543 // is false, otherwise we could continuously create and destroy PseudoEl ements |
| 2503 // when RenderObject::isChildAllowed on our parent returns false for the | 2544 // when RenderObject::isChildAllowed on our parent returns false for the |
| 2504 // PseudoElement's renderer for each style recalc. | 2545 // PseudoElement's renderer for each style recalc. |
| 2505 if (!renderer() || !pseudoElementRendererIsNeeded(renderer()->getCachedP seudoStyle(pseudoId))) | 2546 if (!renderer() || !pseudoElementRendererIsNeeded(renderer()->getCachedP seudoStyle(pseudoId))) |
| 2506 elementRareData()->setPseudoElement(pseudoId, nullptr); | 2547 elementRareData()->setPseudoElement(pseudoId, nullptr); |
| 2507 } else if (change >= UpdatePseudoElements) { | 2548 } else if (change >= UpdatePseudoElements) { |
| 2508 createPseudoElementIfNeeded(pseudoId); | 2549 createPseudoElementIfNeeded(pseudoId); |
| 2509 } | 2550 } |
| 2510 } | 2551 } |
| 2511 | 2552 |
| 2512 void Element::createPseudoElementIfNeeded(PseudoId pseudoId) | 2553 void Element::createPseudoElementIfNeeded(PseudoId pseudoId) |
| (...skipping 22 matching lines...) Expand all Loading... | |
| 2535 return hasRareData() ? elementRareData()->pseudoElement(pseudoId) : 0; | 2576 return hasRareData() ? elementRareData()->pseudoElement(pseudoId) : 0; |
| 2536 } | 2577 } |
| 2537 | 2578 |
| 2538 RenderObject* Element::pseudoElementRenderer(PseudoId pseudoId) const | 2579 RenderObject* Element::pseudoElementRenderer(PseudoId pseudoId) const |
| 2539 { | 2580 { |
| 2540 if (PseudoElement* element = pseudoElement(pseudoId)) | 2581 if (PseudoElement* element = pseudoElement(pseudoId)) |
| 2541 return element->renderer(); | 2582 return element->renderer(); |
| 2542 return 0; | 2583 return 0; |
| 2543 } | 2584 } |
| 2544 | 2585 |
| 2586 void Element::clearFirstLetterPseudoElement() | |
| 2587 { | |
| 2588 elementRareData()->setPseudoElement(FIRST_LETTER, nullptr); | |
| 2589 setNeedsStyleRecalc(SubtreeStyleChange); | |
|
esprehn
2014/09/30 09:00:30
Woah, this is crazy, why does removing it cause a
dsinclair
2014/09/30 21:46:33
Done. This call has been removed.
| |
| 2590 } | |
| 2591 | |
| 2545 bool Element::matches(const String& selectors, ExceptionState& exceptionState) | 2592 bool Element::matches(const String& selectors, ExceptionState& exceptionState) |
| 2546 { | 2593 { |
| 2547 SelectorQuery* selectorQuery = document().selectorQueryCache().add(AtomicStr ing(selectors), document(), exceptionState); | 2594 SelectorQuery* selectorQuery = document().selectorQueryCache().add(AtomicStr ing(selectors), document(), exceptionState); |
| 2548 if (!selectorQuery) | 2595 if (!selectorQuery) |
| 2549 return false; | 2596 return false; |
| 2550 return selectorQuery->matches(*this); | 2597 return selectorQuery->matches(*this); |
| 2551 } | 2598 } |
| 2552 | 2599 |
| 2553 DOMTokenList& Element::classList() | 2600 DOMTokenList& Element::classList() |
| 2554 { | 2601 { |
| (...skipping 705 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3260 const WrapperTypeInfo* wrapperType = wrapperTypeInfo(); | 3307 const WrapperTypeInfo* wrapperType = wrapperTypeInfo(); |
| 3261 v8::Handle<v8::Object> wrapper = V8DOMWrapper::createWrapper(creationContext , wrapperType, toScriptWrappableBase(), isolate); | 3308 v8::Handle<v8::Object> wrapper = V8DOMWrapper::createWrapper(creationContext , wrapperType, toScriptWrappableBase(), isolate); |
| 3262 if (wrapper.IsEmpty()) | 3309 if (wrapper.IsEmpty()) |
| 3263 return v8::Handle<v8::Object>(); | 3310 return v8::Handle<v8::Object>(); |
| 3264 | 3311 |
| 3265 wrapper->SetPrototype(binding->prototype()); | 3312 wrapper->SetPrototype(binding->prototype()); |
| 3266 | 3313 |
| 3267 return V8DOMWrapper::associateObjectWithWrapperNonTemplate(this, wrapperType , wrapper, isolate); | 3314 return V8DOMWrapper::associateObjectWithWrapperNonTemplate(this, wrapperType , wrapper, isolate); |
| 3268 } | 3315 } |
| 3269 | 3316 |
| 3317 | |
| 3318 // CSS 2.1 http://www.w3.org/TR/CSS21/selector.html#first-letter | |
| 3319 // "Punctuation (i.e, characters defined in Unicode [UNICODE] in the "open" (Ps) , "close" (Pe), | |
| 3320 // "initial" (Pi). "final" (Pf) and "other" (Po) punctuation classes), that prec edes or follows the first letter should be included" | |
| 3321 static inline bool isPunctuationForFirstLetter(UChar c) | |
|
esprehn
2014/09/30 09:00:30
Lets put all this code in it's own class.
dsinclair
2014/09/30 21:46:33
Done.
| |
| 3322 { | |
| 3323 CharCategory charCategory = category(c); | |
| 3324 return charCategory == Punctuation_Open | |
| 3325 || charCategory == Punctuation_Close | |
| 3326 || charCategory == Punctuation_InitialQuote | |
| 3327 || charCategory == Punctuation_FinalQuote | |
| 3328 || charCategory == Punctuation_Other; | |
| 3329 } | |
| 3330 | |
| 3331 static inline bool isSpaceOrNewline(UChar c) | |
| 3332 { | |
| 3333 // Use isASCIISpace() for basic Latin-1. | |
| 3334 // This will include newlines, which aren't included in Unicode DirWS. | |
| 3335 return c <= 0x7F ? WTF::isASCIISpace(c) : WTF::Unicode::direction(c) == WTF: :Unicode::WhiteSpaceNeutral; | |
| 3336 } | |
| 3337 | |
| 3338 static inline bool isSpaceForFirstLetter(UChar c) | |
| 3339 { | |
| 3340 return isSpaceOrNewline(c) || c == noBreakSpace; | |
| 3341 } | |
| 3342 | |
| 3343 unsigned Element::firstLetterLength(const String& text) const | |
|
esprehn
2014/09/30 09:00:30
ditto. Own class, own files.
dsinclair
2014/09/30 21:46:33
Done.
| |
| 3344 { | |
| 3345 unsigned length = 0; | |
| 3346 unsigned textLength = text.length(); | |
| 3347 | |
| 3348 // Account for leading spaces first. | |
| 3349 while (length < textLength && isSpaceForFirstLetter(text[length])) | |
| 3350 length++; | |
| 3351 | |
| 3352 // Now account for leading punctuation. | |
| 3353 while (length < textLength && isPunctuationForFirstLetter(text[length])) | |
| 3354 length++; | |
| 3355 | |
| 3356 // Bail if we didn't find a letter before the end of the text or before a sp ace. | |
| 3357 if (isSpaceForFirstLetter(text[length]) || (textLength && length == textLeng th)) | |
| 3358 return 0; | |
| 3359 | |
| 3360 // Account the next character for first letter. | |
| 3361 length++; | |
| 3362 | |
| 3363 // Keep looking allowed punctuation for the :first-letter. | |
| 3364 for (unsigned scanLength = length; scanLength < textLength; ++scanLength) { | |
| 3365 UChar c = text[scanLength]; | |
| 3366 | |
| 3367 if (!isPunctuationForFirstLetter(c)) | |
| 3368 break; | |
| 3369 | |
| 3370 length = scanLength + 1; | |
| 3371 } | |
| 3372 | |
| 3373 // FIXME: If textLength is 0, length may still be 1! | |
| 3374 return length; | |
| 3375 } | |
| 3376 | |
| 3377 RenderObject* Element::firstLetterTextRenderer() const | |
|
esprehn
2014/09/30 09:00:30
ditto
dsinclair
2014/09/30 21:46:33
Done.
| |
| 3378 { | |
| 3379 RenderObject* parentRenderer = renderer(); | |
| 3380 if (!parentRenderer | |
| 3381 || !parentRenderer->style()->hasPseudoStyle(FIRST_LETTER) | |
| 3382 || !parentRenderer->canHaveGeneratedChildren() | |
| 3383 || !(parentRenderer->isRenderBlockFlow() || parentRenderer->isRenderButt on())) | |
| 3384 return nullptr; | |
| 3385 | |
| 3386 // Drill down into our children and look for our first text child. | |
| 3387 RenderObject* firstLetterTextRenderer = parentRenderer->slowFirstChild(); | |
| 3388 while (firstLetterTextRenderer) { | |
| 3389 | |
| 3390 // This can be called when the first letter renderer is already in the t ree. We do not | |
| 3391 // want to consider that renderer for our text renderer so we go the sib ling. | |
| 3392 if (firstLetterTextRenderer->style() && firstLetterTextRenderer->style() ->styleType() == FIRST_LETTER) { | |
| 3393 firstLetterTextRenderer = firstLetterTextRenderer->nextSibling(); | |
| 3394 | |
| 3395 } else if (firstLetterTextRenderer->isText()) { | |
| 3396 // FIXME: If there is leading punctuation in a different RenderText than | |
| 3397 // the first letter, we'll not apply the correct style to it. | |
| 3398 if (firstLetterLength(toRenderText(firstLetterTextRenderer)->origina lText())) | |
| 3399 break; | |
| 3400 firstLetterTextRenderer = firstLetterTextRenderer->nextSibling(); | |
| 3401 | |
| 3402 } else if (firstLetterTextRenderer->isListMarker()) { | |
| 3403 firstLetterTextRenderer = firstLetterTextRenderer->nextSibling(); | |
| 3404 | |
| 3405 } else if (firstLetterTextRenderer->isFloatingOrOutOfFlowPositioned()) { | |
| 3406 if (firstLetterTextRenderer->style()->styleType() == FIRST_LETTER) { | |
| 3407 firstLetterTextRenderer = firstLetterTextRenderer->slowFirstChil d(); | |
| 3408 break; | |
| 3409 } | |
| 3410 firstLetterTextRenderer = firstLetterTextRenderer->nextSibling(); | |
| 3411 | |
| 3412 } else if (firstLetterTextRenderer->isReplaced() || firstLetterTextRende rer->isRenderButton() | |
| 3413 || firstLetterTextRenderer->isMenuList()) { | |
| 3414 return nullptr; | |
| 3415 | |
| 3416 } else if (firstLetterTextRenderer->style()->hasPseudoStyle(FIRST_LETTER ) | |
| 3417 && firstLetterTextRenderer->canHaveGeneratedChildren()) { | |
| 3418 // Let the child handle it when it's attached. | |
| 3419 return nullptr; | |
| 3420 | |
| 3421 } else { | |
| 3422 firstLetterTextRenderer = firstLetterTextRenderer->slowFirstChild(); | |
| 3423 } | |
| 3424 } | |
| 3425 | |
| 3426 // No first letter text to display, we're done. | |
| 3427 // FIXME: This black-list of disallowed RenderText subclasses is fragile. | |
| 3428 // Should counter be on this list? What about RenderTextFragment? | |
| 3429 if (!firstLetterTextRenderer || !firstLetterTextRenderer->isText() | |
| 3430 || firstLetterTextRenderer->isBR() || toRenderText(firstLetterTextRender er)->isWordBreak()) | |
| 3431 return nullptr; | |
| 3432 | |
| 3433 return firstLetterTextRenderer; | |
| 3434 } | |
| 3435 | |
| 3270 } // namespace blink | 3436 } // namespace blink |
| OLD | NEW |