Skip to content

Commit

Permalink
Serialize content of style information element with URL replacement
Browse files Browse the repository at this point in the history
https://bugs.webkit.org/show_bug.cgi?id=264022
rdar://116883064

Reviewed by Ryosuke Niwa.

Instead of directly appending plain text content of style information element to markup, building up a contents string
from rules in the element and appending the string to markup. In this way, we could replace the subresource URLs on
demand.

API test: WebArchive.SaveResourcesStyle

* Source/WebCore/css/CSSFontFaceRule.cpp:
(WebCore::CSSFontFaceRule::cssText const):
(WebCore::CSSFontFaceRule::cssTextWithReplacementURLs const):
(WebCore::CSSFontFaceRule::cssTextInternal const):
* Source/WebCore/css/CSSFontFaceRule.h:
* Source/WebCore/css/CSSFontFaceSrcValue.cpp:
(WebCore::CSSFontFaceSrcResourceValue::customSetReplacementURLForSubresources):
(WebCore::CSSFontFaceSrcResourceValue::customClearReplacementURLForSubresources):
(WebCore::CSSFontFaceSrcResourceValue::customCSSText const):
* Source/WebCore/css/CSSFontFaceSrcValue.h:
* Source/WebCore/css/CSSImageValue.cpp:
(WebCore::CSSImageValue::customSetReplacementURLForSubresources):
(WebCore::CSSImageValue::customClearReplacementURLForSubresources):
(WebCore::CSSImageValue::customCSSText const):
* Source/WebCore/css/CSSImageValue.h:
* Source/WebCore/css/CSSRule.h:
(WebCore::CSSRule::cssTextWithReplacementURLs const):
* Source/WebCore/css/CSSStyleRule.cpp:
(WebCore::CSSStyleRule::cssText const):
(WebCore::CSSStyleRule::cssTextForRules const):
(WebCore::CSSStyleRule::cssTextWithReplacementURLs const):
(WebCore::CSSStyleRule::cssTextForRulesWithReplacementURLs const):
(WebCore::CSSStyleRule::cssTextInternal const):
(WebCore::CSSStyleRule::cssTextForDeclsAndRules const): Deleted.
* Source/WebCore/css/CSSStyleRule.h:
* Source/WebCore/css/CSSValue.cpp:
(WebCore::CSSValue::setReplacementURLForSubresources):
(WebCore::CSSValue::clearReplacementURLForSubresources):
* Source/WebCore/css/CSSValue.h:
(WebCore::CSSValue::customSetReplacementURLForSubresources):
(WebCore::CSSValue::customClearReplacementURLForSubresources):
* Source/WebCore/css/CSSValueList.cpp:
(WebCore::CSSValueContainingVector::customSetReplacementURLForSubresources):
(WebCore::CSSValueContainingVector::customClearReplacementURLForSubresources):
* Source/WebCore/css/CSSValueList.h:
* Source/WebCore/css/StyleProperties.cpp:
(WebCore::StyleProperties::setReplacementURLForSubresources):
(WebCore::StyleProperties::clearReplacementURLForSubresources):
* Source/WebCore/css/StyleProperties.h:
* Source/WebCore/editing/MarkupAccumulator.cpp:
(WebCore::MarkupAccumulator::appendContentsForNode):
(WebCore::MarkupAccumulator::serializeNodesWithNamespaces):
* Source/WebCore/editing/MarkupAccumulator.h:
* Source/WebCore/html/HTMLStyleElement.cpp:
(WebCore::HTMLStyleElement::addSubresourceAttributeURLs const):
(WebCore::HTMLStyleElement::textContentWithReplacementURLs const):
* Source/WebCore/html/HTMLStyleElement.h:
* Tools/TestWebKitAPI/Tests/WebKitCocoa/CreateWebArchive.mm:

Canonical link: https://commits.webkit.org/270114@main
  • Loading branch information
szewai committed Nov 2, 2023
1 parent 8dedd16 commit 3520ab7
Show file tree
Hide file tree
Showing 20 changed files with 292 additions and 32 deletions.
17 changes: 16 additions & 1 deletion Source/WebCore/css/CSSFontFaceRule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,24 @@ CSSStyleDeclaration& CSSFontFaceRule::style()

String CSSFontFaceRule::cssText() const
{
String declarations = m_fontFaceRule->properties().asText();
return cssTextInternal(m_fontFaceRule->properties().asText());
}

String CSSFontFaceRule::cssTextWithReplacementURLs(const HashMap<String, String>& replacementURLStrings) const
{
auto mutableStyleProperties = m_fontFaceRule->properties().mutableCopy();
mutableStyleProperties->setReplacementURLForSubresources(replacementURLStrings);
auto declarations = mutableStyleProperties->asText();
mutableStyleProperties->clearReplacementURLForSubresources();

return cssTextInternal(declarations);
}

String CSSFontFaceRule::cssTextInternal(const String& declarations) const
{
if (declarations.isEmpty())
return "@font-face { }"_s;

return makeString("@font-face { ", declarations, " }");
}

Expand Down
2 changes: 2 additions & 0 deletions Source/WebCore/css/CSSFontFaceRule.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ class CSSFontFaceRule final : public CSSRule {

StyleRuleType styleRuleType() const final { return StyleRuleType::FontFace; }
String cssText() const final;
String cssTextWithReplacementURLs(const HashMap<String, String>&) const final;
String cssTextInternal(const String& declarations) const;
void reattach(StyleRuleBase&) final;

Ref<StyleRuleFontFace> m_fontFaceRule;
Expand Down
17 changes: 16 additions & 1 deletion Source/WebCore/css/CSSFontFaceSrcValue.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -123,10 +123,25 @@ bool CSSFontFaceSrcResourceValue::customTraverseSubresources(const Function<bool
return m_cachedFont && handler(*m_cachedFont);
}

void CSSFontFaceSrcResourceValue::customSetReplacementURLForSubresources(const HashMap<String, String>& replacementURLStrings)
{
auto replacementURLString = replacementURLStrings.get(m_location.resolvedURL.string());
if (!replacementURLString.isNull())
m_replacementURLString = replacementURLString;
}

void CSSFontFaceSrcResourceValue::customClearReplacementURLForSubresources()
{
m_replacementURLString = { };
}

String CSSFontFaceSrcResourceValue::customCSSText() const
{
StringBuilder builder;
builder.append(serializeURL(m_location.specifiedURLString));
if (!m_replacementURLString.isEmpty())
builder.append(serializeURL(m_replacementURLString));
else
builder.append(serializeURL(m_location.specifiedURLString));
if (!m_format.isEmpty())
builder.append(" format(", serializeString(m_format), ')');
if (!m_technologies.isEmpty()) {
Expand Down
3 changes: 3 additions & 0 deletions Source/WebCore/css/CSSFontFaceSrcValue.h
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,8 @@ class CSSFontFaceSrcResourceValue final : public CSSValue {

String customCSSText() const;
bool customTraverseSubresources(const Function<bool(const CachedResource&)>&) const;
void customSetReplacementURLForSubresources(const HashMap<String, String>&);
void customClearReplacementURLForSubresources();
bool equals(const CSSFontFaceSrcResourceValue&) const;

private:
Expand All @@ -126,6 +128,7 @@ class CSSFontFaceSrcResourceValue final : public CSSValue {
Vector<FontTechnology> m_technologies;
LoadedFromOpaqueSource m_loadedFromOpaqueSource { LoadedFromOpaqueSource::No };
CachedResourceHandle<CachedFont> m_cachedFont;
String m_replacementURLString;
};

} // namespace WebCore
Expand Down
16 changes: 16 additions & 0 deletions Source/WebCore/css/CSSImageValue.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,18 @@ bool CSSImageValue::customTraverseSubresources(const Function<bool(const CachedR
return m_cachedImage && *m_cachedImage && handler(**m_cachedImage);
}

void CSSImageValue::customSetReplacementURLForSubresources(const HashMap<String, String>& replacementURLStrings)
{
auto replacementURLString = replacementURLStrings.get(m_location.resolvedURL.string());
if (!replacementURLString.isNull())
m_replacementURLString = replacementURLString;
}

void CSSImageValue::customClearReplacementURLForSubresources()
{
m_replacementURLString = { };
}

bool CSSImageValue::equals(const CSSImageValue& other) const
{
return m_location == other.m_location;
Expand All @@ -132,6 +144,10 @@ String CSSImageValue::customCSSText() const
{
if (m_isInvalid)
return ""_s;

if (!m_replacementURLString.isEmpty())
return serializeURL(m_replacementURLString);

return serializeURL(m_location.specifiedURLString);
}

Expand Down
3 changes: 3 additions & 0 deletions Source/WebCore/css/CSSImageValue.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ class CSSImageValue final : public CSSValue {
Ref<DeprecatedCSSOMValue> createDeprecatedCSSOMWrapper(CSSStyleDeclaration&) const;

bool customTraverseSubresources(const Function<bool(const CachedResource&)>&) const;
void customSetReplacementURLForSubresources(const HashMap<String, String>&);
void customClearReplacementURLForSubresources();

bool equals(const CSSImageValue&) const;

Expand All @@ -80,6 +82,7 @@ class CSSImageValue final : public CSSValue {
LoadedFromOpaqueSource m_loadedFromOpaqueSource { LoadedFromOpaqueSource::No };
RefPtr<CSSImageValue> m_unresolvedValue;
bool m_isInvalid { false };
String m_replacementURLString;
};

} // namespace WebCore
Expand Down
1 change: 1 addition & 0 deletions Source/WebCore/css/CSSRule.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ class CSSRule : public RefCounted<CSSRule> {

virtual StyleRuleType styleRuleType() const = 0;
virtual String cssText() const = 0;
virtual String cssTextWithReplacementURLs(const HashMap<String, String>&) const { return cssText(); }
virtual void reattach(StyleRuleBase&) = 0;

void setParentStyleSheet(CSSStyleSheet*);
Expand Down
61 changes: 44 additions & 17 deletions Source/WebCore/css/CSSStyleRule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#include "CSSRuleList.h"
#include "CSSStyleSheet.h"
#include "DeclaredStylePropertyMap.h"
#include "MutableStyleProperties.h"
#include "PropertySetCSSStyleDeclaration.h"
#include "RuleSet.h"
#include "StyleProperties.h"
Expand Down Expand Up @@ -146,48 +147,74 @@ Vector<Ref<StyleRuleBase>> CSSStyleRule::nestedRules() const
// https://w3c.github.io/csswg-drafts/cssom-1/#serialize-a-css-rule
String CSSStyleRule::cssText() const
{
StringBuilder builder;
builder.append(selectorText());
builder.append(" {");
auto declarationsString = m_styleRule->properties().asText();
StringBuilder declarations;
StringBuilder rules;
declarations.append(declarationsString);
cssTextForRules(rules);

auto declsString = m_styleRule->properties().asText();
StringBuilder decls;
return cssTextInternal(declarations, rules);
}

void CSSStyleRule::cssTextForRules(StringBuilder& rules) const
{
for (unsigned index = 0 ; index < nestedRules().size() ; index++)
rules.append("\n ", item(index)->cssText());
}

String CSSStyleRule::cssTextWithReplacementURLs(const HashMap<String, String>& replacementURLStrings) const
{
StringBuilder declarations;
StringBuilder rules;

decls.append(declsString);
cssTextForDeclsAndRules(decls, rules);
auto mutableStyleProperties = m_styleRule->properties().mutableCopy();
mutableStyleProperties->setReplacementURLForSubresources(replacementURLStrings);
auto declarationsString = mutableStyleProperties->asText();
mutableStyleProperties->clearReplacementURLForSubresources();

declarations.append(declarationsString);
cssTextForRulesWithReplacementURLs(rules, replacementURLStrings);

return cssTextInternal(declarations, rules);
}

if (decls.isEmpty() && rules.isEmpty()) {
void CSSStyleRule::cssTextForRulesWithReplacementURLs(StringBuilder& rules, const HashMap<String, String>& replacementURLStrings) const
{
for (unsigned index = 0 ; index < nestedRules().size() ; index++)
rules.append("\n ", item(index)->cssTextWithReplacementURLs(replacementURLStrings));
}

String CSSStyleRule::cssTextInternal(StringBuilder& declarations, StringBuilder& rules) const
{
StringBuilder builder;
builder.append(selectorText());
builder.append(" {");

if (declarations.isEmpty() && rules.isEmpty()) {
builder.append(" }");
return builder.toString();
}

if (rules.isEmpty()) {
builder.append(' ');
builder.append(decls);
builder.append(declarations);
builder.append(" }");
return builder.toString();
}

if (decls.isEmpty()) {
if (declarations.isEmpty()) {
builder.append(rules);
builder.append("\n}");
return builder.toString();
}

builder.append("\n ");
builder.append(decls);
builder.append(declarations);
builder.append(rules);
builder.append("\n}");
return builder.toString();
}

void CSSStyleRule::cssTextForDeclsAndRules(StringBuilder&, StringBuilder& rules) const
{
for (unsigned index = 0 ; index < nestedRules().size() ; index++)
rules.append("\n ", item(index)->cssText());
}

// FIXME: share all methods below with CSSGroupingRule.

void CSSStyleRule::reattach(StyleRuleBase& rule)
Expand Down
5 changes: 4 additions & 1 deletion Source/WebCore/css/CSSStyleRule.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,11 +63,14 @@ class CSSStyleRule final : public CSSRule, public CanMakeWeakPtr<CSSStyleRule> {

StyleRuleType styleRuleType() const final { return StyleRuleType::Style; }
String cssText() const final;
String cssTextWithReplacementURLs(const HashMap<String, String>&) const final;
String cssTextInternal(StringBuilder& declarations, StringBuilder& rules) const;
void reattach(StyleRuleBase&) final;

String generateSelectorText() const;
Vector<Ref<StyleRuleBase>> nestedRules() const;
void cssTextForDeclsAndRules(StringBuilder& decls, StringBuilder& rules) const;
void cssTextForRules(StringBuilder& rules) const;
void cssTextForRulesWithReplacementURLs(StringBuilder& rules, const HashMap<String, String>& replacementURLStrings) const;

Ref<StyleRule> m_styleRule;
Ref<DeclaredStylePropertyMap> m_styleMap;
Expand Down
14 changes: 14 additions & 0 deletions Source/WebCore/css/CSSValue.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,20 @@ bool CSSValue::traverseSubresources(const Function<bool(const CachedResource&)>&
});
}

void CSSValue::setReplacementURLForSubresources(const HashMap<String, String>& replacementURLStrings)
{
return visitDerived([&](auto& value) {
return value.customSetReplacementURLForSubresources(replacementURLStrings);
});
}

void CSSValue::clearReplacementURLForSubresources()
{
return visitDerived([&](auto& value) {
return value.customClearReplacementURLForSubresources();
});
}

ComputedStyleDependencies CSSValue::computedStyleDependencies() const
{
ComputedStyleDependencies dependencies;
Expand Down
5 changes: 5 additions & 0 deletions Source/WebCore/css/CSSValue.h
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,8 @@ class CSSValue {
Ref<DeprecatedCSSOMValue> createDeprecatedCSSOMWrapper(CSSStyleDeclaration&) const;

bool traverseSubresources(const Function<bool(const CachedResource&)>&) const;
void setReplacementURLForSubresources(const HashMap<String, String>&);
void clearReplacementURLForSubresources();

// What properties does this value rely on (eg, font-size for em units)
ComputedStyleDependencies computedStyleDependencies() const;
Expand Down Expand Up @@ -188,6 +190,9 @@ class CSSValue {
inline bool isValueID() const;
inline CSSValueID valueID() const;

void customSetReplacementURLForSubresources(const HashMap<String, String>&) { }
void customClearReplacementURLForSubresources() { }

protected:
static const size_t ClassTypeBits = 6;

Expand Down
12 changes: 12 additions & 0 deletions Source/WebCore/css/CSSValueList.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -278,4 +278,16 @@ bool CSSValueContainingVector::customTraverseSubresources(const Function<bool(co
return false;
}

void CSSValueContainingVector::customSetReplacementURLForSubresources(const HashMap<String, String>& replacementURLStrings)
{
for (auto& value : *this)
const_cast<CSSValue&>(value).setReplacementURLForSubresources(replacementURLStrings);
}

void CSSValueContainingVector::customClearReplacementURLForSubresources()
{
for (auto& value : *this)
const_cast<CSSValue&>(value).clearReplacementURLForSubresources();
}

} // namespace WebCore
2 changes: 2 additions & 0 deletions Source/WebCore/css/CSSValueList.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@ class CSSValueContainingVector : public CSSValue {
using CSSValue::separatorCSSText;

bool customTraverseSubresources(const Function<bool(const CachedResource&)>&) const;
void customSetReplacementURLForSubresources(const HashMap<String, String>&);
void customClearReplacementURLForSubresources();

CSSValueListBuilder copyValues() const;

Expand Down
12 changes: 12 additions & 0 deletions Source/WebCore/css/StyleProperties.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -349,6 +349,18 @@ bool StyleProperties::traverseSubresources(const Function<bool(const CachedResou
return false;
}

void StyleProperties::setReplacementURLForSubresources(const HashMap<String, String>& replacementURLStrings)
{
for (auto property : *this)
property.value()->setReplacementURLForSubresources(replacementURLStrings);
}

void StyleProperties::clearReplacementURLForSubresources()
{
for (auto property : *this)
property.value()->clearReplacementURLForSubresources();
}

bool StyleProperties::propertyMatches(CSSPropertyID propertyID, const CSSValue* propertyValue) const
{
int foundPropertyIndex = findPropertyIndex(propertyID);
Expand Down
2 changes: 2 additions & 0 deletions Source/WebCore/css/StyleProperties.h
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,8 @@ class StyleProperties : public RefCounted<StyleProperties> {
bool isMutable() const { return m_isMutable; }

bool traverseSubresources(const Function<bool(const CachedResource&)>& handler) const;
void setReplacementURLForSubresources(const HashMap<String, String>&);
void clearReplacementURLForSubresources();

static unsigned averageSizeInBytes();

Expand Down
14 changes: 13 additions & 1 deletion Source/WebCore/editing/MarkupAccumulator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
#include "HTMLFrameElement.h"
#include "HTMLIFrameElement.h"
#include "HTMLNames.h"
#include "HTMLStyleElement.h"
#include "HTMLTemplateElement.h"
#include "NodeName.h"
#include "ProcessingInstruction.h"
Expand Down Expand Up @@ -208,6 +209,16 @@ String MarkupAccumulator::serializeNodes(Node& targetNode, SerializedNodes root,
return m_markup.toString();
}

bool MarkupAccumulator::appendContentsForNode(StringBuilder& result, const Node& targetNode)
{
if (m_replacementURLStrings.isEmpty() || !targetNode.hasTagName(styleTag))
return false;

auto& styleElement = downcast<HTMLStyleElement>(targetNode);
result.append(styleElement.textContentWithReplacementURLs(m_replacementURLStrings));
return true;
}

void MarkupAccumulator::serializeNodesWithNamespaces(Node& targetNode, SerializedNodes root, const Namespaces* namespaces, Vector<QualifiedName>* tagNamesToSkip)
{
WTF::Vector<Namespaces> namespaceStack;
Expand Down Expand Up @@ -248,8 +259,9 @@ void MarkupAccumulator::serializeNodesWithNamespaces(Node& targetNode, Serialize
}
}

bool shouldSkipChidren = appendContentsForNode(m_markup, *current);
auto firstChild = current->hasTagName(templateTag) ? downcast<HTMLTemplateElement>(*current).content().firstChild() : current->firstChild();
if (firstChild) {
if (!shouldSkipChidren && firstChild) {
current = firstChild;
namespaceStack.append(namespaceStack.last());
continue;
Expand Down
1 change: 1 addition & 0 deletions Source/WebCore/editing/MarkupAccumulator.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ class MarkupAccumulator {
virtual void appendEndTag(StringBuilder&, const Element&);
virtual void appendCustomAttributes(StringBuilder&, const Element&, Namespaces*);
virtual void appendText(StringBuilder&, const Text&);
virtual bool appendContentsForNode(StringBuilder& result, const Node&);

void appendOpenTag(StringBuilder&, const Element&, Namespaces*);
void appendCloseTag(StringBuilder&, const Element&);
Expand Down
Loading

0 comments on commit 3520ab7

Please sign in to comment.