[svg] Parse text attributes
Convert font-family, font-size, font-style and font-weight to
presentation attributes, and add parsing utils.
Bug: skia:10840
Change-Id: I1acdb59bc95fe46e67ed0f499dd0732420016663
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/328436
Commit-Queue: Florin Malita <fmalita@google.com>
Reviewed-by: Tyler Denniston <tdenniston@google.com>
diff --git a/modules/svg/include/SkSVGAttribute.h b/modules/svg/include/SkSVGAttribute.h
index 3c129d0..cd64e91 100644
--- a/modules/svg/include/SkSVGAttribute.h
+++ b/modules/svg/include/SkSVGAttribute.h
@@ -89,6 +89,11 @@
SkTLazy<SkSVGColorType> fColor;
+ SkTLazy<SkSVGFontFamily> fFontFamily;
+ SkTLazy<SkSVGFontStyle> fFontStyle;
+ SkTLazy<SkSVGFontSize> fFontSize;
+ SkTLazy<SkSVGFontWeight> fFontWeight;
+
// TODO(tdenniston): add SkSVGStopColor
// uninherited
diff --git a/modules/svg/include/SkSVGAttributeParser.h b/modules/svg/include/SkSVGAttributeParser.h
index 81ae1d3..1ac9aac 100644
--- a/modules/svg/include/SkSVGAttributeParser.h
+++ b/modules/svg/include/SkSVGAttributeParser.h
@@ -32,6 +32,11 @@
bool parseVisibility(SkSVGVisibility*);
bool parseDashArray(SkSVGDashArray*);
+ bool parseFontFamily(SkSVGFontFamily*);
+ bool parseFontSize(SkSVGFontSize*);
+ bool parseFontStyle(SkSVGFontStyle*);
+ bool parseFontWeight(SkSVGFontWeight*);
+
private:
// Stack-only
void* operator new(size_t) = delete;
@@ -67,6 +72,9 @@
template <typename Func, typename T>
bool parseParenthesized(const char* prefix, Func, T* result);
+ template <typename T, typename TArray>
+ bool parseEnumMap(const TArray& arr, T* result);
+
// The current position in the input string.
const char* fCurPos;
diff --git a/modules/svg/include/SkSVGNode.h b/modules/svg/include/SkSVGNode.h
index 2e92c6b..8f493d2 100644
--- a/modules/svg/include/SkSVGNode.h
+++ b/modules/svg/include/SkSVGNode.h
@@ -38,6 +38,29 @@
kUse
};
+#define SVG_PRES_ATTR(attr_name, attr_type, attr_inherited) \
+ const attr_type* get##attr_name() const { \
+ return fPresentationAttributes.f##attr_name.getMaybeNull(); \
+ } \
+ void set##attr_name(const attr_type& v) { \
+ if (!attr_inherited || v.type() != attr_type::Type::kInherit) { \
+ fPresentationAttributes.f##attr_name.set(v); \
+ } else { \
+ /* kInherited values are semantically equivalent to \
+ the absence of a local presentation attribute.*/ \
+ fPresentationAttributes.f##attr_name.reset(); \
+ } \
+ } \
+ void set##attr_name(attr_type&& v) { \
+ if (!attr_inherited || v.type() != attr_type::Type::kInherit) { \
+ fPresentationAttributes.f##attr_name.set(std::move(v)); \
+ } else { \
+ /* kInherited values are semantically equivalent to \
+ the absence of a local presentation attribute.*/ \
+ fPresentationAttributes.f##attr_name.reset(); \
+ } \
+ }
+
class SkSVGNode : public SkRefCnt {
public:
~SkSVGNode() override;
@@ -70,6 +93,11 @@
void setStrokeWidth(const SkSVGLength&);
void setVisibility(const SkSVGVisibility&);
+ SVG_PRES_ATTR(FontFamily, SkSVGFontFamily, true)
+ SVG_PRES_ATTR(FontStyle , SkSVGFontStyle , true)
+ SVG_PRES_ATTR(FontSize , SkSVGFontSize , true)
+ SVG_PRES_ATTR(FontWeight, SkSVGFontWeight, true)
+
protected:
SkSVGNode(SkSVGTag);
diff --git a/modules/svg/include/SkSVGText.h b/modules/svg/include/SkSVGText.h
index 9336f73..55716cd 100644
--- a/modules/svg/include/SkSVGText.h
+++ b/modules/svg/include/SkSVGText.h
@@ -10,12 +10,12 @@
#include "include/core/SkFont.h"
#include "include/utils/SkTextUtils.h"
-#include "modules/svg/include/SkSVGShape.h"
+#include "modules/svg/include/SkSVGTransformableNode.h"
#include "modules/svg/include/SkSVGTypes.h"
class SkRRect;
-class SkSVGText final : public SkSVGShape {
+class SkSVGText final : public SkSVGTransformableNode {
public:
~SkSVGText() override = default;
static sk_sp<SkSVGText> Make() {
@@ -23,18 +23,14 @@
void setX(const SkSVGLength&);
void setY(const SkSVGLength&);
- void setFontFamily(const SkSVGStringType&);
- void setFontSize(const SkSVGLength&);
- void setFontStyle(const SkSVGStringType&);
- void setFontWeight(const SkSVGStringType&);
void setText(const SkSVGStringType&);
void setTextAnchor(const SkSVGStringType&);
protected:
void onSetAttribute(SkSVGAttribute, const SkSVGValue&) override;
- void onDraw(SkCanvas*, const SkSVGLengthContext&, const SkPaint&,
- SkPathFillType) const override;
+ void onRender(const SkSVGRenderContext&) const override;
+ void appendChild(sk_sp<SkSVGNode>) override;
SkPath onAsPath(const SkSVGRenderContext&) const override;
@@ -42,16 +38,16 @@
private:
SkSVGText();
- SkSVGLength fX = SkSVGLength(0);
- SkSVGLength fY = SkSVGLength(0);
- SkSVGStringType fText;
- sk_sp<SkTypeface> fTypeface;
- SkSVGLength fFontSize;
- SkSVGStringType fFontFamily;
- SkSVGStringType fFontStyle;
- SkSVGStringType fFontWeight;
+
+ SkFont resolveFont(const SkSVGRenderContext&) const;
+
+ SkSVGLength fX = SkSVGLength(0);
+ SkSVGLength fY = SkSVGLength(0);
+ SkSVGStringType fText;
+ sk_sp<SkTypeface> fTypeface;
SkTextUtils::Align fTextAlign = SkTextUtils::Align::kLeft_Align;
- using INHERITED = SkSVGShape;
+
+ using INHERITED = SkSVGTransformableNode;
};
#endif // SkSVGText_DEFINED
diff --git a/modules/svg/include/SkSVGTypes.h b/modules/svg/include/SkSVGTypes.h
index d4563d1..e0ea73e 100644
--- a/modules/svg/include/SkSVGTypes.h
+++ b/modules/svg/include/SkSVGTypes.h
@@ -308,4 +308,112 @@
SkSVGColorType fColor;
};
+class SkSVGFontFamily {
+public:
+ enum class Type {
+ kFamily,
+ kInherit,
+ };
+
+ SkSVGFontFamily() : fType(Type::kInherit) {}
+ explicit SkSVGFontFamily(const char family[])
+ : fType(Type::kFamily)
+ , fFamily(family) {}
+
+ bool operator==(const SkSVGFontFamily& other) const {
+ return fType == other.fType && fFamily == other.fFamily;
+ }
+ bool operator!=(const SkSVGFontFamily& other) const { return !(*this == other); }
+
+ Type type() const { return fType; }
+
+ const SkString& family() const { return fFamily; }
+
+private:
+ Type fType;
+ SkString fFamily;
+};
+
+class SkSVGFontStyle {
+public:
+ enum class Type {
+ kNormal,
+ kItalic,
+ kOblique,
+ kInherit,
+ };
+
+ SkSVGFontStyle() : fType(Type::kInherit) {}
+ explicit SkSVGFontStyle(Type t) : fType(t) {}
+
+ bool operator==(const SkSVGFontStyle& other) const {
+ return fType == other.fType;
+ }
+ bool operator!=(const SkSVGFontStyle& other) const { return !(*this == other); }
+
+ Type type() const { return fType; }
+
+private:
+ Type fType;
+};
+
+class SkSVGFontSize {
+public:
+ enum class Type {
+ kLength,
+ kInherit,
+ };
+
+ SkSVGFontSize() : fType(Type::kInherit), fSize(0) {}
+ explicit SkSVGFontSize(const SkSVGLength& s)
+ : fType(Type::kLength)
+ , fSize(s) {}
+
+ bool operator==(const SkSVGFontSize& other) const {
+ return fType == other.fType && fSize == other.fSize;
+ }
+ bool operator!=(const SkSVGFontSize& other) const { return !(*this == other); }
+
+ Type type() const { return fType; }
+
+ const SkSVGLength& size() const { return fSize; }
+
+private:
+ Type fType;
+ SkSVGLength fSize;
+};
+
+class SkSVGFontWeight {
+public:
+ enum class Type {
+ k100,
+ k200,
+ k300,
+ k400,
+ k500,
+ k600,
+ k700,
+ k800,
+ k900,
+ kNormal,
+ kBold,
+ kBolder,
+ kLighter,
+ kInherit,
+ };
+
+ SkSVGFontWeight() : fType(Type::kInherit) {}
+ explicit SkSVGFontWeight(Type t) : fType(t) {}
+
+ bool operator==(const SkSVGFontWeight& other) const {
+ return fType == other.fType;
+ }
+ bool operator!=(const SkSVGFontWeight& other) const { return !(*this == other); }
+
+ Type type() const { return fType; }
+
+private:
+ Type fType;
+};
+
#endif // SkSVGTypes_DEFINED
diff --git a/modules/svg/include/SkSVGValue.h b/modules/svg/include/SkSVGValue.h
index 7b74cd0..0144a70 100644
--- a/modules/svg/include/SkSVGValue.h
+++ b/modules/svg/include/SkSVGValue.h
@@ -22,6 +22,10 @@
kColor,
kDashArray,
kFillRule,
+ kFontFamily,
+ kFontSize,
+ kFontStyle,
+ kFontWeight,
kLength,
kLineCap,
kLineJoin,
@@ -94,4 +98,9 @@
using SkSVGVisibilityValue = SkSVGWrapperValue<SkSVGVisibility , SkSVGValue::Type::kVisibility>;
using SkSVGDashArrayValue = SkSVGWrapperValue<SkSVGDashArray , SkSVGValue::Type::kDashArray >;
+using SkSVGFontFamilyValue = SkSVGWrapperValue<SkSVGFontFamily , SkSVGValue::Type::kFontFamily>;
+using SkSVGFontSizeValue = SkSVGWrapperValue<SkSVGFontSize , SkSVGValue::Type::kFontSize >;
+using SkSVGFontStyleValue = SkSVGWrapperValue<SkSVGFontStyle , SkSVGValue::Type::kFontStyle >;
+using SkSVGFontWeightValue = SkSVGWrapperValue<SkSVGFontWeight , SkSVGValue::Type::kFontWeight>;
+
#endif // SkSVGValue_DEFINED
diff --git a/modules/svg/src/SkSVGAttribute.cpp b/modules/svg/src/SkSVGAttribute.cpp
index 5bdb65b..0ccea49 100644
--- a/modules/svg/src/SkSVGAttribute.cpp
+++ b/modules/svg/src/SkSVGAttribute.cpp
@@ -28,5 +28,10 @@
result.fColor.set(SkSVGColorType(SK_ColorBLACK));
+ result.fFontFamily.init("Sans");
+ result.fFontStyle.init(SkSVGFontStyle::Type::kNormal);
+ result.fFontSize.init(SkSVGLength(24));
+ result.fFontWeight.init(SkSVGFontWeight(SkSVGFontWeight::Type::kNormal));
+
return result;
}
diff --git a/modules/svg/src/SkSVGAttributeParser.cpp b/modules/svg/src/SkSVGAttributeParser.cpp
index 9914456..18acdf4 100644
--- a/modules/svg/src/SkSVGAttributeParser.cpp
+++ b/modules/svg/src/SkSVGAttributeParser.cpp
@@ -33,6 +33,17 @@
} // namespace
+template <typename T, typename TArray>
+bool SkSVGAttributeParser::parseEnumMap(const TArray& arr, T* result) {
+ for (size_t i = 0; i < SK_ARRAY_COUNT(arr); ++i) {
+ if (this->parseExpectedStringToken(std::get<0>(arr[i]))) {
+ *result = std::get<1>(arr[i]);
+ return true;
+ }
+ }
+ return false;
+}
+
SkSVGAttributeParser::SkSVGAttributeParser(const char attributeString[])
: fCurPos(attributeString) {}
@@ -710,3 +721,90 @@
return parsedValue && this->parseEOSToken();
}
+
+// https://www.w3.org/TR/SVG11/text.html#FontFamilyProperty
+bool SkSVGAttributeParser::parseFontFamily(SkSVGFontFamily* family) {
+ bool parsedValue = false;
+ if (this->parseExpectedStringToken("inherit")) {
+ *family = SkSVGFontFamily();
+ parsedValue = true;
+ } else {
+ // The spec allows specifying a comma-separated list for explicit fallback order.
+ // For now, we only use the first entry and rely on the font manager to handle fallback.
+ const auto* comma = strchr(fCurPos, ',');
+ auto family_name = comma ? SkString(fCurPos, comma - fCurPos)
+ : SkString(fCurPos);
+ *family = SkSVGFontFamily(family_name.c_str());
+ fCurPos += strlen(fCurPos);
+ parsedValue = true;
+ }
+
+ return parsedValue && this->parseEOSToken();
+}
+
+// https://www.w3.org/TR/SVG11/text.html#FontSizeProperty
+bool SkSVGAttributeParser::parseFontSize(SkSVGFontSize* size) {
+ bool parsedValue = false;
+ if (this->parseExpectedStringToken("inherit")) {
+ *size = SkSVGFontSize();
+ parsedValue = true;
+ } else {
+ SkSVGLength length;
+ if (this->parseLength(&length)) {
+ *size = SkSVGFontSize(length);
+ parsedValue = true;
+ }
+ }
+
+ return parsedValue && this->parseEOSToken();
+}
+
+// https://www.w3.org/TR/SVG11/text.html#FontStyleProperty
+bool SkSVGAttributeParser::parseFontStyle(SkSVGFontStyle* style) {
+ static constexpr std::tuple<const char*, SkSVGFontStyle::Type> gStyleMap[] = {
+ { "normal" , SkSVGFontStyle::Type::kNormal },
+ { "italic" , SkSVGFontStyle::Type::kItalic },
+ { "oblique", SkSVGFontStyle::Type::kOblique },
+ { "inherit", SkSVGFontStyle::Type::kInherit },
+ };
+
+ bool parsedValue = false;
+ SkSVGFontStyle::Type type;
+
+ if (this->parseEnumMap(gStyleMap, &type)) {
+ *style = SkSVGFontStyle(type);
+ parsedValue = true;
+ }
+
+ return parsedValue && this->parseEOSToken();
+}
+
+// https://www.w3.org/TR/SVG11/text.html#FontWeightProperty
+bool SkSVGAttributeParser::parseFontWeight(SkSVGFontWeight* weight) {
+ static constexpr std::tuple<const char*, SkSVGFontWeight::Type> gWeightMap[] = {
+ { "normal" , SkSVGFontWeight::Type::kNormal },
+ { "bold" , SkSVGFontWeight::Type::kBold },
+ { "bolder" , SkSVGFontWeight::Type::kBolder },
+ { "lighter", SkSVGFontWeight::Type::kLighter },
+ { "100" , SkSVGFontWeight::Type::k100 },
+ { "200" , SkSVGFontWeight::Type::k200 },
+ { "300" , SkSVGFontWeight::Type::k300 },
+ { "400" , SkSVGFontWeight::Type::k400 },
+ { "500" , SkSVGFontWeight::Type::k500 },
+ { "600" , SkSVGFontWeight::Type::k600 },
+ { "700" , SkSVGFontWeight::Type::k700 },
+ { "800" , SkSVGFontWeight::Type::k800 },
+ { "900" , SkSVGFontWeight::Type::k900 },
+ { "inherit", SkSVGFontWeight::Type::kInherit },
+ };
+
+ bool parsedValue = false;
+ SkSVGFontWeight::Type type;
+
+ if (this->parseEnumMap(gWeightMap, &type)) {
+ *weight = SkSVGFontWeight(type);
+ parsedValue = true;
+ }
+
+ return parsedValue && this->parseEOSToken();
+}
diff --git a/modules/svg/src/SkSVGDOM.cpp b/modules/svg/src/SkSVGDOM.cpp
index c833a6a..8ab5ade 100644
--- a/modules/svg/src/SkSVGDOM.cpp
+++ b/modules/svg/src/SkSVGDOM.cpp
@@ -248,6 +248,54 @@
return true;
}
+bool SetFontFamilyAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
+ const char* stringValue) {
+ SkSVGFontFamily family;
+ SkSVGAttributeParser parser(stringValue);
+ if (!parser.parseFontFamily(&family)) {
+ return false;
+ }
+
+ node->setAttribute(attr, SkSVGFontFamilyValue(family));
+ return true;
+}
+
+bool SetFontSizeAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
+ const char* stringValue) {
+ SkSVGFontSize size;
+ SkSVGAttributeParser parser(stringValue);
+ if (!parser.parseFontSize(&size)) {
+ return false;
+ }
+
+ node->setAttribute(attr, SkSVGFontSizeValue(size));
+ return true;
+}
+
+bool SetFontStyleAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
+ const char* stringValue) {
+ SkSVGFontStyle style;
+ SkSVGAttributeParser parser(stringValue);
+ if (!parser.parseFontStyle(&style)) {
+ return false;
+ }
+
+ node->setAttribute(attr, SkSVGFontStyleValue(style));
+ return true;
+}
+
+bool SetFontWeightAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
+ const char* stringValue) {
+ SkSVGFontWeight weight;
+ SkSVGAttributeParser parser(stringValue);
+ if (!parser.parseFontWeight(&weight)) {
+ return false;
+ }
+
+ node->setAttribute(attr, SkSVGFontWeightValue(weight));
+ return true;
+}
+
SkString TrimmedString(const char* first, const char* last) {
SkASSERT(first);
SkASSERT(last);
@@ -335,10 +383,10 @@
{ "fill" , { SkSVGAttribute::kFill , SetPaintAttribute }},
{ "fill-opacity" , { SkSVGAttribute::kFillOpacity , SetNumberAttribute }},
{ "fill-rule" , { SkSVGAttribute::kFillRule , SetFillRuleAttribute }},
- { "font-family" , { SkSVGAttribute::kFontFamily , SetStringAttribute }},
- { "font-size" , { SkSVGAttribute::kFontSize , SetLengthAttribute }},
- { "font-style" , { SkSVGAttribute::kFontStyle , SetStringAttribute }},
- { "font-weight" , { SkSVGAttribute::kFontWeight , SetStringAttribute }},
+ { "font-family" , { SkSVGAttribute::kFontFamily , SetFontFamilyAttribute }},
+ { "font-size" , { SkSVGAttribute::kFontSize , SetFontSizeAttribute }},
+ { "font-style" , { SkSVGAttribute::kFontStyle , SetFontStyleAttribute }},
+ { "font-weight" , { SkSVGAttribute::kFontWeight , SetFontWeightAttribute }},
// focal point x & y
{ "fx" , { SkSVGAttribute::kFx , SetLengthAttribute }},
{ "fy" , { SkSVGAttribute::kFy , SetLengthAttribute }},
@@ -404,8 +452,8 @@
ConstructionContext(const ConstructionContext& other, const sk_sp<SkSVGNode>& newParent)
: fParent(newParent.get()), fIDMapper(other.fIDMapper) {}
- const SkSVGNode* fParent;
- SkSVGIDMapper* fIDMapper;
+ SkSVGNode* fParent;
+ SkSVGIDMapper* fIDMapper;
};
bool set_string_attribute(const sk_sp<SkSVGNode>& node, const char* name, const char* value) {
@@ -452,7 +500,10 @@
if (elemType == SkDOM::kText_Type) {
SkASSERT(dom.countChildren(xmlNode) == 0);
- // TODO: text handling
+ // TODO: add type conversion helper to SkSVGNode
+ if (ctx.fParent->tag() == SkSVGTag::kText) {
+ static_cast<SkSVGText*>(ctx.fParent)->setText(SkString(dom.getName(xmlNode)));
+ }
return nullptr;
}
diff --git a/modules/svg/src/SkSVGNode.cpp b/modules/svg/src/SkSVGNode.cpp
index d634722..ce05aa5 100644
--- a/modules/svg/src/SkSVGNode.cpp
+++ b/modules/svg/src/SkSVGNode.cpp
@@ -169,6 +169,26 @@
this->setFillRule(*fillRule);
}
break;
+ case SkSVGAttribute::kFontFamily:
+ if (const SkSVGFontFamilyValue* family = v.as<SkSVGFontFamilyValue>()) {
+ this->setFontFamily(*family);
+ }
+ break;
+ case SkSVGAttribute::kFontSize:
+ if (const SkSVGFontSizeValue* size = v.as<SkSVGFontSizeValue>()) {
+ this->setFontSize(*size);
+ }
+ break;
+ case SkSVGAttribute::kFontStyle:
+ if (const SkSVGFontStyleValue* style = v.as<SkSVGFontStyleValue>()) {
+ this->setFontStyle(*style);
+ }
+ break;
+ case SkSVGAttribute::kFontWeight:
+ if (const SkSVGFontWeightValue* style = v.as<SkSVGFontWeightValue>()) {
+ this->setFontWeight(*style);
+ }
+ break;
case SkSVGAttribute::kOpacity:
if (const SkSVGNumberValue* opacity = v.as<SkSVGNumberValue>()) {
this->setOpacity(*opacity);
diff --git a/modules/svg/src/SkSVGRenderContext.cpp b/modules/svg/src/SkSVGRenderContext.cpp
index 4607f67..759c5cf 100644
--- a/modules/svg/src/SkSVGRenderContext.cpp
+++ b/modules/svg/src/SkSVGRenderContext.cpp
@@ -274,6 +274,34 @@
// Not part of the SkPaint state; applied via 'currentColor' color value
}
+template <>
+void commitToPaint<SkSVGAttribute::kFontFamily>(const SkSVGPresentationAttributes&,
+ const SkSVGRenderContext&,
+ SkSVGPresentationContext*) {
+ // Not part of the SkPaint state; applied at render time.
+}
+
+template <>
+void commitToPaint<SkSVGAttribute::kFontSize>(const SkSVGPresentationAttributes&,
+ const SkSVGRenderContext&,
+ SkSVGPresentationContext*) {
+ // Not part of the SkPaint state; applied at render time.
+}
+
+template <>
+void commitToPaint<SkSVGAttribute::kFontStyle>(const SkSVGPresentationAttributes&,
+ const SkSVGRenderContext&,
+ SkSVGPresentationContext*) {
+ // Not part of the SkPaint state; applied at render time.
+}
+
+template <>
+void commitToPaint<SkSVGAttribute::kFontWeight>(const SkSVGPresentationAttributes&,
+ const SkSVGRenderContext&,
+ SkSVGPresentationContext*) {
+ // Not part of the SkPaint state; applied at render time.
+}
+
} // namespace
SkSVGPresentationContext::SkSVGPresentationContext()
@@ -351,6 +379,10 @@
ApplyLazyInheritedAttribute(Fill);
ApplyLazyInheritedAttribute(FillOpacity);
ApplyLazyInheritedAttribute(FillRule);
+ ApplyLazyInheritedAttribute(FontFamily);
+ ApplyLazyInheritedAttribute(FontSize);
+ ApplyLazyInheritedAttribute(FontStyle);
+ ApplyLazyInheritedAttribute(FontWeight);
ApplyLazyInheritedAttribute(ClipRule);
ApplyLazyInheritedAttribute(Stroke);
ApplyLazyInheritedAttribute(StrokeDashOffset);
diff --git a/modules/svg/src/SkSVGText.cpp b/modules/svg/src/SkSVGText.cpp
index b2d8704..4dde8b8 100644
--- a/modules/svg/src/SkSVGText.cpp
+++ b/modules/svg/src/SkSVGText.cpp
@@ -8,6 +8,7 @@
#include "modules/svg/include/SkSVGText.h"
#include "include/core/SkCanvas.h"
+#include "include/core/SkFontMgr.h"
#include "include/core/SkFontStyle.h"
#include "include/core/SkString.h"
#include "modules/svg/include/SkSVGRenderContext.h"
@@ -19,47 +20,6 @@
void SkSVGText::setY(const SkSVGLength& y) { fY = y; }
-void SkSVGText::setFontFamily(const SkSVGStringType& font_family) {
- if (fFontFamily != font_family) {
- fFontFamily = font_family;
-
- this->loadFont();
- }
-}
-
-void SkSVGText::loadFont() {
- SkFontStyle style;
- if (fFontWeight.equals("bold")) {
- if (fFontStyle.equals("italic")) {
- style = SkFontStyle::BoldItalic();
- } else {
- style = SkFontStyle::Bold();
- }
- } else if (fFontStyle.equals("italic")) {
- style = SkFontStyle::Italic();
- }
-
- fTypeface = SkTypeface::MakeFromName(fFontFamily.c_str(), style);
-}
-
-void SkSVGText::setFontSize(const SkSVGLength& size) { fFontSize = size; }
-
-void SkSVGText::setFontStyle(const SkSVGStringType& font_style) {
- if (fFontStyle != font_style) {
- fFontStyle = font_style;
-
- this->loadFont();
- }
-}
-
-void SkSVGText::setFontWeight(const SkSVGStringType& font_weight) {
- if (fFontWeight != font_weight) {
- fFontWeight = font_weight;
-
- this->loadFont();
- }
-}
-
void SkSVGText::setText(const SkSVGStringType& text) { fText = text; }
void SkSVGText::setTextAnchor(const SkSVGStringType& text_anchor) {
@@ -72,11 +32,79 @@
}
}
-void SkSVGText::onDraw(SkCanvas* canvas, const SkSVGLengthContext& lctx,
- const SkPaint& paint, SkPathFillType) const {
- SkFont font(fTypeface, fFontSize.value());
- SkTextUtils::DrawString(canvas, fText.c_str(), fX.value(), fY.value(),
- font, paint, fTextAlign);
+SkFont SkSVGText::resolveFont(const SkSVGRenderContext& ctx) const {
+ auto weight = [](const SkSVGFontWeight& w) {
+ switch (w.type()) {
+ case SkSVGFontWeight::Type::k100: return SkFontStyle::kThin_Weight;
+ case SkSVGFontWeight::Type::k200: return SkFontStyle::kExtraLight_Weight;
+ case SkSVGFontWeight::Type::k300: return SkFontStyle::kLight_Weight;
+ case SkSVGFontWeight::Type::k400: return SkFontStyle::kNormal_Weight;
+ case SkSVGFontWeight::Type::k500: return SkFontStyle::kMedium_Weight;
+ case SkSVGFontWeight::Type::k600: return SkFontStyle::kSemiBold_Weight;
+ case SkSVGFontWeight::Type::k700: return SkFontStyle::kBold_Weight;
+ case SkSVGFontWeight::Type::k800: return SkFontStyle::kExtraBold_Weight;
+ case SkSVGFontWeight::Type::k900: return SkFontStyle::kBlack_Weight;
+ case SkSVGFontWeight::Type::kNormal: return SkFontStyle::kNormal_Weight;
+ case SkSVGFontWeight::Type::kBold: return SkFontStyle::kBold_Weight;
+ case SkSVGFontWeight::Type::kBolder: return SkFontStyle::kExtraBold_Weight;
+ case SkSVGFontWeight::Type::kLighter: return SkFontStyle::kLight_Weight;
+ case SkSVGFontWeight::Type::kInherit: {
+ SkASSERT(false);
+ return SkFontStyle::kNormal_Weight;
+ }
+ }
+ SkUNREACHABLE;
+ };
+
+ auto slant = [](const SkSVGFontStyle& s) {
+ switch (s.type()) {
+ case SkSVGFontStyle::Type::kNormal: return SkFontStyle::kUpright_Slant;
+ case SkSVGFontStyle::Type::kItalic: return SkFontStyle::kItalic_Slant;
+ case SkSVGFontStyle::Type::kOblique: return SkFontStyle::kOblique_Slant;
+ case SkSVGFontStyle::Type::kInherit: {
+ SkASSERT(false);
+ return SkFontStyle::kUpright_Slant;
+ }
+ }
+ SkUNREACHABLE;
+ };
+
+ const auto& family = ctx.presentationContext().fInherited.fFontFamily->family();
+ const SkFontStyle style(weight(*ctx.presentationContext().fInherited.fFontWeight),
+ SkFontStyle::kNormal_Width,
+ slant(*ctx.presentationContext().fInherited.fFontStyle));
+
+ const auto size =
+ ctx.lengthContext().resolve(ctx.presentationContext().fInherited.fFontSize->size(),
+ SkSVGLengthContext::LengthType::kVertical);
+
+ // TODO: allow clients to pass an external fontmgr.
+ SkFont font(SkTypeface::MakeFromName(family.c_str(), style), size);
+ font.setHinting(SkFontHinting::kNone);
+ font.setSubpixel(true);
+ font.setLinearMetrics(true);
+ font.setBaselineSnap(false);
+ font.setEdging(SkFont::Edging::kAntiAlias);
+
+ return font;
+}
+
+void SkSVGText::onRender(const SkSVGRenderContext& ctx) const {
+ const auto font = this->resolveFont(ctx);
+
+ if (const SkPaint* fillPaint = ctx.fillPaint()) {
+ SkTextUtils::DrawString(ctx.canvas(), fText.c_str(), fX.value(), fY.value(), font,
+ *fillPaint, fTextAlign);
+ }
+
+ if (const SkPaint* strokePaint = ctx.strokePaint()) {
+ SkTextUtils::DrawString(ctx.canvas(), fText.c_str(), fX.value(), fY.value(), font,
+ *strokePaint, fTextAlign);
+ }
+}
+
+void SkSVGText::appendChild(sk_sp<SkSVGNode>) {
+ // TODO
}
SkPath SkSVGText::onAsPath(const SkSVGRenderContext& ctx) const {
@@ -106,25 +134,6 @@
this->setTextAnchor(*text_anchor);
}
break;
- case SkSVGAttribute::kFontFamily:
- if (const auto* font_family = v.as<SkSVGStringValue>()) {
- this->setFontFamily(*font_family);
- }
- break;
- case SkSVGAttribute::kFontWeight:
- if (const auto* font_weight = v.as<SkSVGStringValue>()) {
- this->setFontWeight(*font_weight);
- }
- break;
- case SkSVGAttribute::kFontSize:
- if (const auto* font_size = v.as<SkSVGLengthValue>()) {
- this->setFontSize(*font_size);
- }
- break;
- case SkSVGAttribute::kFontStyle:
- if (const auto* font_style = v.as<SkSVGStringValue>()) {
- this->setFontStyle(*font_style);
- }
break;
default:
this->INHERITED::onSetAttribute(attr, v);