1 /* 2 * Copyright (C) 2012 Google Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are 6 * met: 7 * 8 * * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * * Neither the name of Google Inc. nor the names of its 11 * contributors may be used to endorse or promote products derived from 12 * this software without specific prior written permission. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 15 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 16 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 17 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 18 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 19 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 20 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27 #include "config.h" 28 #include "core/dom/PseudoElement.h" 29 30 #include "core/inspector/InspectorInstrumentation.h" 31 #include "core/rendering/RenderObject.h" 32 #include "core/rendering/RenderQuote.h" 33 #include "core/rendering/style/ContentData.h" 34 35 namespace blink { 36 37 const QualifiedName& pseudoElementTagName(PseudoId pseudoId) 38 { 39 switch (pseudoId) { 40 case AFTER: { 41 DEFINE_STATIC_LOCAL(QualifiedName, after, (nullAtom, "<pseudo:after>", nullAtom)); 42 return after; 43 } 44 case BEFORE: { 45 DEFINE_STATIC_LOCAL(QualifiedName, before, (nullAtom, "<pseudo:before>", nullAtom)); 46 return before; 47 } 48 case BACKDROP: { 49 DEFINE_STATIC_LOCAL(QualifiedName, backdrop, (nullAtom, "<pseudo:backdrop>", nullAtom)); 50 return backdrop; 51 } 52 default: { 53 ASSERT_NOT_REACHED(); 54 } 55 } 56 DEFINE_STATIC_LOCAL(QualifiedName, name, (nullAtom, "<pseudo>", nullAtom)); 57 return name; 58 } 59 60 String PseudoElement::pseudoElementNameForEvents(PseudoId pseudoId) 61 { 62 DEFINE_STATIC_LOCAL(const String, after, ("::after")); 63 DEFINE_STATIC_LOCAL(const String, before, ("::before")); 64 switch (pseudoId) { 65 case AFTER: 66 return after; 67 case BEFORE: 68 return before; 69 default: 70 return emptyString(); 71 } 72 } 73 74 PseudoElement::PseudoElement(Element* parent, PseudoId pseudoId) 75 : Element(pseudoElementTagName(pseudoId), &parent->document(), CreateElement) 76 , m_pseudoId(pseudoId) 77 { 78 ASSERT(pseudoId != NOPSEUDO); 79 setParentOrShadowHostNode(parent); 80 setHasCustomStyleCallbacks(); 81 } 82 83 PassRefPtr<RenderStyle> PseudoElement::customStyleForRenderer() 84 { 85 return parentOrShadowHostElement()->renderer()->getCachedPseudoStyle(m_pseudoId); 86 } 87 88 void PseudoElement::dispose() 89 { 90 ASSERT(parentOrShadowHostElement()); 91 92 InspectorInstrumentation::pseudoElementDestroyed(this); 93 94 ASSERT(!nextSibling()); 95 ASSERT(!previousSibling()); 96 97 detach(); 98 RefPtrWillBeRawPtr<Element> parent = parentOrShadowHostElement(); 99 setParentOrShadowHostNode(0); 100 removedFrom(parent.get()); 101 } 102 103 void PseudoElement::attach(const AttachContext& context) 104 { 105 ASSERT(!renderer()); 106 107 Element::attach(context); 108 109 RenderObject* renderer = this->renderer(); 110 if (!renderer) 111 return; 112 RenderStyle* style = renderer->style(); 113 if (style->styleType() != BEFORE && style->styleType() != AFTER) 114 return; 115 ASSERT(style->contentData()); 116 117 for (const ContentData* content = style->contentData(); content; content = content->next()) { 118 RenderObject* child = content->createRenderer(document(), style); 119 if (renderer->isChildAllowed(child, style)) { 120 renderer->addChild(child); 121 if (child->isQuote()) 122 toRenderQuote(child)->attachQuote(); 123 } else 124 child->destroy(); 125 } 126 } 127 128 bool PseudoElement::rendererIsNeeded(const RenderStyle& style) 129 { 130 return pseudoElementRendererIsNeeded(&style); 131 } 132 133 void PseudoElement::didRecalcStyle(StyleRecalcChange) 134 { 135 if (!renderer()) 136 return; 137 138 // The renderers inside pseudo elements are anonymous so they don't get notified of recalcStyle and must have 139 // the style propagated downward manually similar to RenderObject::propagateStyleToAnonymousChildren. 140 RenderObject* renderer = this->renderer(); 141 for (RenderObject* child = renderer->nextInPreOrder(renderer); child; child = child->nextInPreOrder(renderer)) { 142 // We only manage the style for the generated content items. 143 if (!child->isText() && !child->isQuote() && !child->isImage()) 144 continue; 145 146 // The style for the RenderTextFragment for first letter is managed by an enclosing block, not by us. 147 if (child->style()->styleType() == FIRST_LETTER) 148 continue; 149 150 child->setPseudoStyle(renderer->style()); 151 } 152 } 153 154 } // namespace 155