void RenderStyle::setContent(PassRefPtr<StringImpl> s, bool add) { if (!s) return; // The string is null. Nothing to do. Just bail. OwnPtr<ContentData>& content = rareNonInheritedData.access()->m_content; ContentData* lastContent = content.get(); while (lastContent && lastContent->next()) lastContent = lastContent->next(); bool reuseContent = !add; if (add && lastContent) { if (lastContent->isText()) { // We can augment the existing string and share this ContentData node. String newStr = lastContent->text(); newStr.append(s.get()); lastContent->setText(newStr.impl()); return; } } ContentData* newContentData = 0; if (reuseContent && content) { content->clear(); newContentData = content.release(); } else newContentData = new ContentData; if (lastContent && !reuseContent) lastContent->setNext(newContentData); else content.set(newContentData); newContentData->setText(s); }
bool StyleRareNonInheritedData::contentDataEquivalent(const StyleRareNonInheritedData& o) const { ContentData* a = m_content.get(); ContentData* b = o.m_content.get(); while (a && b && *a == *b) { a = a->next(); b = b->next(); } return !a && !b; }
PassOwnPtr<ContentData> ContentData::clone() const { OwnPtr<ContentData> result = cloneInternal(); ContentData* lastNewData = result.get(); for (const ContentData* contentData = next(); contentData; contentData = contentData->next()) { OwnPtr<ContentData> newData = contentData->cloneInternal(); lastNewData->setNext(newData.release()); lastNewData = lastNewData->next(); } return result.release(); }
std::unique_ptr<ContentData> ContentData::clone() const { auto result = cloneInternal(); ContentData* lastNewData = result.get(); for (const ContentData* contentData = next(); contentData; contentData = contentData->next()) { auto newData = contentData->cloneInternal(); lastNewData->setNext(std::move(newData)); lastNewData = lastNewData->next(); } return result; }
ContentData* ContentData::clone() const { ContentData* result = cloneInternal(); ContentData* lastNewData = result; for (const ContentData* contentData = next(); contentData; contentData = contentData->next()) { ContentData* newData = contentData->cloneInternal(); lastNewData->setNext(newData); lastNewData = lastNewData->next(); } return result; }
ContentData* RenderStyle::prepareToSetContent(StringImpl* string, bool add) { OwnPtr<ContentData>& content = rareNonInheritedData.access()->m_content; ContentData* lastContent = content.get(); while (lastContent && lastContent->next()) lastContent = lastContent->next(); if (string && add && lastContent && lastContent->isText()) { // Augment the existing string and share the existing ContentData node. String newText = lastContent->text(); newText.append(string); lastContent->setText(newText.impl()); return 0; } bool reuseContent = !add; OwnPtr<ContentData> newContentData; if (reuseContent && content) { content->clear(); newContentData = content.release(); } else newContentData = adoptPtr(new ContentData); ContentData* result = newContentData.get(); if (lastContent && !reuseContent) lastContent->setNext(newContentData.release()); else content = newContentData.release(); return result; }
void RenderStyle::setContent(CounterContent* c, bool add) { if (!c) return; OwnPtr<ContentData>& content = rareNonInheritedData.access()->m_content; ContentData* lastContent = content.get(); while (lastContent && lastContent->next()) lastContent = lastContent->next(); bool reuseContent = !add; ContentData* newContentData = 0; if (reuseContent && content) { content->clear(); newContentData = content.release(); } else newContentData = new ContentData; if (lastContent && !reuseContent) lastContent->setNext(newContentData); else content.set(newContentData); newContentData->setCounter(c); }
void RenderStyle::setContent(PassRefPtr<StyleImage> image, bool add) { if (!image) return; // The object is null. Nothing to do. Just bail. OwnPtr<ContentData>& content = rareNonInheritedData.access()->m_content; ContentData* lastContent = content.get(); while (lastContent && lastContent->next()) lastContent = lastContent->next(); bool reuseContent = !add; ContentData* newContentData; if (reuseContent && content) { content->clear(); newContentData = content.release(); } else newContentData = new ContentData; if (lastContent && !reuseContent) lastContent->setNext(newContentData); else content.set(newContentData); newContentData->setImage(image); }
bool ContentData::dataEquivalent(const ContentData& other) const { if (type() != other.type()) return false; switch (type()) { case CONTENT_NONE: return true; break; case CONTENT_TEXT: return equal(text(), other.text()); break; case CONTENT_OBJECT: return StyleImage::imagesEquivalent(image(), other.image()); break; case CONTENT_COUNTER: return *counter() == *other.counter(); break; } ASSERT_NOT_REACHED(); return false; }
void StyleResourceLoader::loadPendingImages(RenderStyle* style, const ElementStyleResources& elementStyleResources) { if (elementStyleResources.pendingImageProperties().isEmpty()) return; PendingImagePropertyMap::const_iterator::Keys end = elementStyleResources.pendingImageProperties().end().keys(); for (PendingImagePropertyMap::const_iterator::Keys it = elementStyleResources.pendingImageProperties().begin().keys(); it != end; ++it) { CSSPropertyID currentProperty = *it; switch (currentProperty) { case CSSPropertyBackgroundImage: { for (FillLayer* backgroundLayer = style->accessBackgroundLayers(); backgroundLayer; backgroundLayer = backgroundLayer->next()) { if (backgroundLayer->image() && backgroundLayer->image()->isPendingImage()) backgroundLayer->setImage(loadPendingImage(static_cast<StylePendingImage*>(backgroundLayer->image()), elementStyleResources.deviceScaleFactor())); } break; } case CSSPropertyContent: { for (ContentData* contentData = const_cast<ContentData*>(style->contentData()); contentData; contentData = contentData->next()) { if (contentData->isImage()) { StyleImage* image = static_cast<ImageContentData*>(contentData)->image(); if (image->isPendingImage()) { RefPtr<StyleImage> loadedImage = loadPendingImage(static_cast<StylePendingImage*>(image), elementStyleResources.deviceScaleFactor()); if (loadedImage) static_cast<ImageContentData*>(contentData)->setImage(loadedImage.release()); } } } break; } case CSSPropertyCursor: { if (CursorList* cursorList = style->cursors()) { for (size_t i = 0; i < cursorList->size(); ++i) { CursorData& currentCursor = cursorList->at(i); if (StyleImage* image = currentCursor.image()) { if (image->isPendingImage()) currentCursor.setImage(loadPendingImage(static_cast<StylePendingImage*>(image), elementStyleResources.deviceScaleFactor())); } } } break; } case CSSPropertyListStyleImage: { if (style->listStyleImage() && style->listStyleImage()->isPendingImage()) style->setListStyleImage(loadPendingImage(static_cast<StylePendingImage*>(style->listStyleImage()), elementStyleResources.deviceScaleFactor())); break; } case CSSPropertyBorderImageSource: { if (style->borderImageSource() && style->borderImageSource()->isPendingImage()) style->setBorderImageSource(loadPendingImage(static_cast<StylePendingImage*>(style->borderImageSource()), elementStyleResources.deviceScaleFactor())); break; } case CSSPropertyWebkitBoxReflect: { if (StyleReflection* reflection = style->boxReflect()) { const NinePieceImage& maskImage = reflection->mask(); if (maskImage.image() && maskImage.image()->isPendingImage()) { RefPtr<StyleImage> loadedImage = loadPendingImage(static_cast<StylePendingImage*>(maskImage.image()), elementStyleResources.deviceScaleFactor()); reflection->setMask(NinePieceImage(loadedImage.release(), maskImage.imageSlices(), maskImage.fill(), maskImage.borderSlices(), maskImage.outset(), maskImage.horizontalRule(), maskImage.verticalRule())); } } break; } case CSSPropertyWebkitMaskBoxImageSource: { if (style->maskBoxImageSource() && style->maskBoxImageSource()->isPendingImage()) style->setMaskBoxImageSource(loadPendingImage(static_cast<StylePendingImage*>(style->maskBoxImageSource()), elementStyleResources.deviceScaleFactor())); break; } case CSSPropertyWebkitMaskImage: { for (FillLayer* maskLayer = style->accessMaskLayers(); maskLayer; maskLayer = maskLayer->next()) { if (maskLayer->image() && maskLayer->image()->isPendingImage()) maskLayer->setImage(loadPendingImage(static_cast<StylePendingImage*>(maskLayer->image()), elementStyleResources.deviceScaleFactor())); } break; } case CSSPropertyWebkitShapeInside: loadPendingShapeImage(style, style->shapeInside()); break; case CSSPropertyWebkitShapeOutside: loadPendingShapeImage(style, style->shapeOutside()); break; default: ASSERT_NOT_REACHED(); } } }
void RenderContainer::updatePseudoChild(RenderStyle::PseudoId type, RenderObject* child) { // In CSS2, before/after pseudo-content cannot nest. Check this first. if (style()->styleType() == RenderStyle::BEFORE || style()->styleType() == RenderStyle::AFTER) return; RenderStyle* pseudo = getPseudoStyle(type); // Whether or not we currently have generated content attached. bool oldContentPresent = child && (child->style()->styleType() == type); // Whether or not we now want generated content. bool newContentWanted = pseudo && pseudo->display() != NONE; // For <q><p/></q>, if this object is the inline continuation of the <q>, we only want to generate // :after content and not :before content. if (type == RenderStyle::BEFORE && isInlineContinuation()) newContentWanted = false; // Similarly, if we're the beginning of a <q>, and there's an inline continuation for our object, // then we don't generate the :after content. if (type == RenderStyle::AFTER && isRenderInline() && continuation()) newContentWanted = false; // If we don't want generated content any longer, or if we have generated content, but it's no longer // identical to the new content data we want to build render objects for, then we nuke all // of the old generated content. if (!newContentWanted || (oldContentPresent && !child->style()->contentDataEquivalent(pseudo))) { // Nuke the child. if (child && child->style()->styleType() == type) { oldContentPresent = false; removeChild(child); child = (type == RenderStyle::BEFORE) ? firstChild() : lastChild(); } } // If we have no pseudo-style or if the pseudo's display type is NONE, then we // have no generated content and can now return. if (!newContentWanted) return; if (isInlineFlow() && pseudo->display() != INLINE) // According to the CSS2 spec (the end of section 12.1), the only allowed // display values for the pseudo style are NONE and INLINE. Since we already // determined that the pseudo is not display NONE, any display other than // inline should be mutated to INLINE. pseudo->setDisplay(INLINE); if (oldContentPresent) { if (child && child->style()->styleType() == type) { // We have generated content present still. We want to walk this content and update our // style information with the new pseudo style. child->setStyle(pseudo); // Note that if we ever support additional types of generated content (which should be way off // in the future), this code will need to be patched. for (RenderObject* genChild = child->firstChild(); genChild; genChild = genChild->nextSibling()) { if (genChild->isText()) // Generated text content is a child whose style also needs to be set to the pseudo // style. genChild->setStyle(pseudo); else { // Images get an empty style that inherits from the pseudo. RenderStyle* style = new (renderArena()) RenderStyle(); style->inheritFrom(pseudo); genChild->setStyle(style); } } } return; // We've updated the generated content. That's all we needed to do. } RenderObject* insertBefore = (type == RenderStyle::BEFORE) ? child : 0; // Generated content consists of a single container that houses multiple children (specified // by the content property). This pseudo container gets the pseudo style set on it. RenderObject* pseudoContainer = 0; // Now walk our list of generated content and create render objects for every type // we encounter. for (ContentData* contentData = pseudo->contentData(); contentData; contentData = contentData->_nextContent) { if (!pseudoContainer) pseudoContainer = RenderFlow::createAnonymousFlow(document(), pseudo); /* anonymous box */ if (contentData->contentType() == CONTENT_TEXT) { RenderText* t = new (renderArena()) RenderTextFragment(document() /*anonymous object */, contentData->contentText()); t->setStyle(pseudo); pseudoContainer->addChild(t); } else if (contentData->contentType() == CONTENT_OBJECT) { RenderImage* img = new (renderArena()) RenderImage(document()); /* Anonymous object */ RenderStyle* style = new (renderArena()) RenderStyle(); style->inheritFrom(pseudo); img->setStyle(style); img->setContentObject(contentData->contentObject()); pseudoContainer->addChild(img); } } if (pseudoContainer) { // Add the pseudo after we've installed all our content, so that addChild will be able to find the text // inside the inline for e.g., first-letter styling. addChild(pseudoContainer, insertBefore); } }
static void loadPendingImages(const PendingResources& pendingResources, Document& document, RenderStyle& style, const Element* element) { for (auto currentProperty : pendingResources.pendingImages.keys()) { switch (currentProperty) { case CSSPropertyBackgroundImage: { for (FillLayer* backgroundLayer = &style.ensureBackgroundLayers(); backgroundLayer; backgroundLayer = backgroundLayer->next()) { auto* styleImage = backgroundLayer->image(); if (is<StylePendingImage>(styleImage)) backgroundLayer->setImage(loadPendingImage(document, *styleImage, element)); } break; } case CSSPropertyContent: { for (ContentData* contentData = const_cast<ContentData*>(style.contentData()); contentData; contentData = contentData->next()) { if (is<ImageContentData>(*contentData)) { auto& styleImage = downcast<ImageContentData>(*contentData).image(); if (is<StylePendingImage>(styleImage)) { if (auto loadedImage = loadPendingImage(document, styleImage, element)) downcast<ImageContentData>(*contentData).setImage(WTFMove(loadedImage)); } } } break; } case CSSPropertyCursor: { if (CursorList* cursorList = style.cursors()) { for (size_t i = 0; i < cursorList->size(); ++i) { CursorData& currentCursor = cursorList->at(i); auto* styleImage = currentCursor.image(); if (is<StylePendingImage>(styleImage)) currentCursor.setImage(loadPendingImage(document, *styleImage, element)); } } break; } case CSSPropertyListStyleImage: { auto* styleImage = style.listStyleImage(); if (is<StylePendingImage>(styleImage)) style.setListStyleImage(loadPendingImage(document, *styleImage, element)); break; } case CSSPropertyBorderImageSource: { auto* styleImage = style.borderImageSource(); if (is<StylePendingImage>(styleImage)) style.setBorderImageSource(loadPendingImage(document, *styleImage, element)); break; } case CSSPropertyWebkitBoxReflect: { if (StyleReflection* reflection = style.boxReflect()) { const NinePieceImage& maskImage = reflection->mask(); auto* styleImage = maskImage.image(); if (is<StylePendingImage>(styleImage)) { auto loadedImage = loadPendingImage(document, *styleImage, element); reflection->setMask(NinePieceImage(WTFMove(loadedImage), maskImage.imageSlices(), maskImage.fill(), maskImage.borderSlices(), maskImage.outset(), maskImage.horizontalRule(), maskImage.verticalRule())); } } break; } case CSSPropertyWebkitMaskBoxImageSource: { auto* styleImage = style.maskBoxImageSource(); if (is<StylePendingImage>(styleImage)) style.setMaskBoxImageSource(loadPendingImage(document, *styleImage, element)); break; } case CSSPropertyWebkitMaskImage: { for (FillLayer* maskLayer = &style.ensureMaskLayers(); maskLayer; maskLayer = maskLayer->next()) { auto* styleImage = maskLayer->image(); if (is<StylePendingImage>(styleImage)) maskLayer->setImage(loadPendingImage(document, *styleImage, element)); } break; } #if ENABLE(CSS_SHAPES) case CSSPropertyWebkitShapeOutside: { if (!style.shapeOutside()) return; StyleImage* image = style.shapeOutside()->image(); if (is<StylePendingImage>(image)) style.shapeOutside()->setImage(loadPendingImage(document, *image, element, LoadPolicy::ShapeOutside)); break; } #endif default: ASSERT_NOT_REACHED(); } } }
void ElementStyleResources::loadPendingImages(ComputedStyle* style) { // We must loop over the properties and then look at the style to see if // a pending image exists, and only load that image. For example: // // <style> // div { background-image: url(a.png); } // div { background-image: url(b.png); } // div { background-image: none; } // </style> // <div></div> // // We call styleImage() for both a.png and b.png adding the // CSSPropertyBackgroundImage property to the m_pendingImageProperties set, // then we null out the background image because of the "none". // // If we eagerly loaded the images we'd fetch a.png, even though it's not // used. If we didn't null check below we'd crash since the none actually // removed all background images. for (CSSPropertyID property : m_pendingImageProperties) { switch (property) { case CSSPropertyBackgroundImage: { for (FillLayer* backgroundLayer = &style->accessBackgroundLayers(); backgroundLayer; backgroundLayer = backgroundLayer->next()) { if (backgroundLayer->image() && backgroundLayer->image()->isPendingImage()) backgroundLayer->setImage(loadPendingImage(toStylePendingImage(backgroundLayer->image()))); } break; } case CSSPropertyContent: { for (ContentData* contentData = const_cast<ContentData*>(style->contentData()); contentData; contentData = contentData->next()) { if (contentData->isImage()) { StyleImage* image = toImageContentData(contentData)->image(); if (image->isPendingImage()) toImageContentData(contentData)->setImage(loadPendingImage(toStylePendingImage(image))); } } break; } case CSSPropertyCursor: { if (CursorList* cursorList = style->cursors()) { for (size_t i = 0; i < cursorList->size(); ++i) { CursorData& currentCursor = cursorList->at(i); if (StyleImage* image = currentCursor.image()) { if (image->isPendingImage()) currentCursor.setImage(loadPendingImage(toStylePendingImage(image))); } } } break; } case CSSPropertyListStyleImage: { if (style->listStyleImage() && style->listStyleImage()->isPendingImage()) style->setListStyleImage(loadPendingImage(toStylePendingImage(style->listStyleImage()))); break; } case CSSPropertyBorderImageSource: { if (style->borderImageSource() && style->borderImageSource()->isPendingImage()) style->setBorderImageSource(loadPendingImage(toStylePendingImage(style->borderImageSource()))); break; } case CSSPropertyWebkitBoxReflect: { if (StyleReflection* reflection = style->boxReflect()) { const NinePieceImage& maskImage = reflection->mask(); if (maskImage.image() && maskImage.image()->isPendingImage()) { RefPtrWillBeRawPtr<StyleImage> loadedImage = loadPendingImage(toStylePendingImage(maskImage.image())); reflection->setMask(NinePieceImage(loadedImage.release(), maskImage.imageSlices(), maskImage.fill(), maskImage.borderSlices(), maskImage.outset(), maskImage.horizontalRule(), maskImage.verticalRule())); } } break; } case CSSPropertyWebkitMaskBoxImageSource: { if (style->maskBoxImageSource() && style->maskBoxImageSource()->isPendingImage()) style->setMaskBoxImageSource(loadPendingImage(toStylePendingImage(style->maskBoxImageSource()))); break; } case CSSPropertyWebkitMaskImage: { for (FillLayer* maskLayer = &style->accessMaskLayers(); maskLayer; maskLayer = maskLayer->next()) { if (maskLayer->image() && maskLayer->image()->isPendingImage()) maskLayer->setImage(loadPendingImage(toStylePendingImage(maskLayer->image()))); } break; } case CSSPropertyShapeOutside: if (style->shapeOutside() && style->shapeOutside()->image() && style->shapeOutside()->image()->isPendingImage()) style->shapeOutside()->setImage(loadPendingImage(toStylePendingImage(style->shapeOutside()->image()), CrossOriginAttributeAnonymous)); break; default: ASSERT_NOT_REACHED(); } } }