[svg] Convert text-anchor to a presentation attribute
https://www.w3.org/TR/SVG11/text.html#TextAnchorProperty Bug: skia:10840 Change-Id: Iff647b62243c42150e873f06215401b5e33705fd Reviewed-on: https://skia-review.googlesource.com/c/skia/+/330125 Commit-Queue: Florin Malita <fmalita@google.com> Reviewed-by: Tyler Denniston <tdenniston@google.com>
This commit is contained in:
parent
72af246561
commit
056385b1c6
@ -95,6 +95,7 @@ struct SkSVGPresentationAttributes {
|
||||
SkTLazy<SkSVGFontStyle> fFontStyle;
|
||||
SkTLazy<SkSVGFontSize> fFontSize;
|
||||
SkTLazy<SkSVGFontWeight> fFontWeight;
|
||||
SkTLazy<SkSVGTextAnchor> fTextAnchor;
|
||||
|
||||
// TODO(tdenniston): add SkSVGStopColor
|
||||
|
||||
|
@ -38,6 +38,7 @@ public:
|
||||
bool parseFontSize(SkSVGFontSize*);
|
||||
bool parseFontStyle(SkSVGFontStyle*);
|
||||
bool parseFontWeight(SkSVGFontWeight*);
|
||||
bool parseTextAnchor(SkSVGTextAnchor*);
|
||||
|
||||
private:
|
||||
// Stack-only
|
||||
|
@ -99,6 +99,7 @@ public:
|
||||
SVG_PRES_ATTR(FontStyle , SkSVGFontStyle , true)
|
||||
SVG_PRES_ATTR(FontSize , SkSVGFontSize , true)
|
||||
SVG_PRES_ATTR(FontWeight, SkSVGFontWeight, true)
|
||||
SVG_PRES_ATTR(TextAnchor, SkSVGTextAnchor, true)
|
||||
|
||||
protected:
|
||||
SkSVGNode(SkSVGTag);
|
||||
|
@ -8,7 +8,6 @@
|
||||
#ifndef SkSVGText_DEFINED
|
||||
#define SkSVGText_DEFINED
|
||||
|
||||
#include "include/core/SkFont.h"
|
||||
#include "include/utils/SkTextUtils.h"
|
||||
#include "modules/svg/include/SkSVGTransformableNode.h"
|
||||
#include "modules/svg/include/SkSVGTypes.h"
|
||||
@ -21,10 +20,9 @@ class SkSVGText final : public SkSVGTransformableNode {
|
||||
static sk_sp<SkSVGText> Make() {
|
||||
return sk_sp<SkSVGText>(new SkSVGText()); }
|
||||
|
||||
void setX(const SkSVGLength&);
|
||||
void setY(const SkSVGLength&);
|
||||
void setText(const SkSVGStringType&);
|
||||
void setTextAnchor(const SkSVGStringType&);
|
||||
SVG_ATTR(X , SkSVGLength , SkSVGLength(0))
|
||||
SVG_ATTR(Y , SkSVGLength , SkSVGLength(0))
|
||||
SVG_ATTR(Text, SkSVGStringType, SkSVGStringType())
|
||||
|
||||
protected:
|
||||
void onSetAttribute(SkSVGAttribute, const SkSVGValue&) override;
|
||||
@ -41,12 +39,6 @@ class SkSVGText final : public SkSVGTransformableNode {
|
||||
|
||||
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 = SkSVGTransformableNode;
|
||||
};
|
||||
|
||||
|
@ -463,4 +463,27 @@ struct SkSVGPreserveAspectRatio {
|
||||
Scale fScale = kMeet;
|
||||
};
|
||||
|
||||
class SkSVGTextAnchor {
|
||||
public:
|
||||
enum class Type {
|
||||
kStart,
|
||||
kMiddle,
|
||||
kEnd,
|
||||
kInherit,
|
||||
};
|
||||
|
||||
SkSVGTextAnchor() : fType(Type::kInherit) {}
|
||||
explicit SkSVGTextAnchor(Type t) : fType(t) {}
|
||||
|
||||
bool operator==(const SkSVGTextAnchor& other) const {
|
||||
return fType == other.fType;
|
||||
}
|
||||
bool operator!=(const SkSVGTextAnchor& other) const { return !(*this == other); }
|
||||
|
||||
Type type() const { return fType; }
|
||||
|
||||
private:
|
||||
Type fType;
|
||||
};
|
||||
|
||||
#endif // SkSVGTypes_DEFINED
|
||||
|
@ -38,6 +38,7 @@ public:
|
||||
kSpreadMethod,
|
||||
kStopColor,
|
||||
kString,
|
||||
kTextAnchor,
|
||||
kTransform,
|
||||
kViewBox,
|
||||
kVisibility,
|
||||
@ -106,6 +107,7 @@ using SkSVGFontFamilyValue = SkSVGWrapperValue<SkSVGFontFamily , SkSVGValue:
|
||||
using SkSVGFontSizeValue = SkSVGWrapperValue<SkSVGFontSize , SkSVGValue::Type::kFontSize >;
|
||||
using SkSVGFontStyleValue = SkSVGWrapperValue<SkSVGFontStyle , SkSVGValue::Type::kFontStyle >;
|
||||
using SkSVGFontWeightValue = SkSVGWrapperValue<SkSVGFontWeight , SkSVGValue::Type::kFontWeight>;
|
||||
using SkSVGTextAnchorValue = SkSVGWrapperValue<SkSVGTextAnchor , SkSVGValue::Type::kTextAnchor>;
|
||||
|
||||
using SkSVGPreserveAspectRatioValue = SkSVGWrapperValue<SkSVGPreserveAspectRatio,
|
||||
SkSVGValue::Type::kPreserveAspectRatio>;
|
||||
|
@ -31,7 +31,8 @@ SkSVGPresentationAttributes SkSVGPresentationAttributes::MakeInitial() {
|
||||
result.fFontFamily.init("Sans");
|
||||
result.fFontStyle.init(SkSVGFontStyle::Type::kNormal);
|
||||
result.fFontSize.init(SkSVGLength(24));
|
||||
result.fFontWeight.init(SkSVGFontWeight(SkSVGFontWeight::Type::kNormal));
|
||||
result.fFontWeight.init(SkSVGFontWeight::Type::kNormal);
|
||||
result.fTextAnchor.init(SkSVGTextAnchor::Type::kStart);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
@ -822,6 +822,26 @@ bool SkSVGAttributeParser::parseFontWeight(SkSVGFontWeight* weight) {
|
||||
return parsedValue && this->parseEOSToken();
|
||||
}
|
||||
|
||||
// https://www.w3.org/TR/SVG11/text.html#TextAnchorProperty
|
||||
bool SkSVGAttributeParser::parseTextAnchor(SkSVGTextAnchor* anchor) {
|
||||
static constexpr std::tuple<const char*, SkSVGTextAnchor::Type> gAnchorMap[] = {
|
||||
{ "start" , SkSVGTextAnchor::Type::kStart },
|
||||
{ "middle" , SkSVGTextAnchor::Type::kMiddle },
|
||||
{ "end" , SkSVGTextAnchor::Type::kEnd },
|
||||
{ "inherit", SkSVGTextAnchor::Type::kInherit},
|
||||
};
|
||||
|
||||
bool parsedValue = false;
|
||||
SkSVGTextAnchor::Type type;
|
||||
|
||||
if (this->parseEnumMap(gAnchorMap, &type)) {
|
||||
*anchor = SkSVGTextAnchor(type);
|
||||
parsedValue = true;
|
||||
}
|
||||
|
||||
return parsedValue && this->parseEOSToken();
|
||||
}
|
||||
|
||||
// https://www.w3.org/TR/SVG11/coords.html#PreserveAspectRatioAttribute
|
||||
bool SkSVGAttributeParser::parsePreserveAspectRatio(SkSVGPreserveAspectRatio* par) {
|
||||
static constexpr std::tuple<const char*, SkSVGPreserveAspectRatio::Align> gAlignMap[] = {
|
||||
|
@ -308,6 +308,19 @@ bool SetFontWeightAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SetTextAnchorAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
|
||||
const char* stringValue) {
|
||||
SkSVGTextAnchor anchor;
|
||||
SkSVGAttributeParser parser(stringValue);
|
||||
|
||||
if (!parser.parseTextAnchor(&anchor)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
node->setAttribute(attr, SkSVGTextAnchorValue(anchor));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SetPreserveAspectRatioAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
|
||||
const char* stringValue) {
|
||||
SkSVGPreserveAspectRatio par;
|
||||
@ -439,7 +452,7 @@ SortedDictionaryEntry<AttrParseInfo> gAttributeParseInfo[] = {
|
||||
{ "stroke-width" , { SkSVGAttribute::kStrokeWidth , SetLengthAttribute }},
|
||||
{ "style" , { SkSVGAttribute::kUnknown , SetStyleAttributes }},
|
||||
{ "text" , { SkSVGAttribute::kText , SetStringAttribute }},
|
||||
{ "text-anchor" , { SkSVGAttribute::kTextAnchor , SetStringAttribute }},
|
||||
{ "text-anchor" , { SkSVGAttribute::kTextAnchor , SetTextAnchorAttribute }},
|
||||
{ "transform" , { SkSVGAttribute::kTransform , SetTransformAttribute }},
|
||||
{ "viewBox" , { SkSVGAttribute::kViewBox , SetViewBoxAttribute }},
|
||||
{ "visibility" , { SkSVGAttribute::kVisibility , SetVisibilityAttribute }},
|
||||
|
@ -238,6 +238,11 @@ void SkSVGNode::onSetAttribute(SkSVGAttribute attr, const SkSVGValue& v) {
|
||||
this->setStrokeWidth(*strokeWidth);
|
||||
}
|
||||
break;
|
||||
case SkSVGAttribute::kTextAnchor:
|
||||
if (const SkSVGTextAnchorValue* anchor = v.as<SkSVGTextAnchorValue>()) {
|
||||
this->setTextAnchor(*anchor);
|
||||
}
|
||||
break;
|
||||
case SkSVGAttribute::kVisibility:
|
||||
if (const SkSVGVisibilityValue* visibility = v.as<SkSVGVisibilityValue>()) {
|
||||
this->setVisibility(*visibility);
|
||||
|
@ -302,6 +302,13 @@ void commitToPaint<SkSVGAttribute::kFontWeight>(const SkSVGPresentationAttribute
|
||||
// Not part of the SkPaint state; applied at render time.
|
||||
}
|
||||
|
||||
template <>
|
||||
void commitToPaint<SkSVGAttribute::kTextAnchor>(const SkSVGPresentationAttributes&,
|
||||
const SkSVGRenderContext&,
|
||||
SkSVGPresentationContext*) {
|
||||
// Not part of the SkPaint state; applied at render time.
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
SkSVGPresentationContext::SkSVGPresentationContext()
|
||||
@ -403,6 +410,7 @@ void SkSVGRenderContext::applyPresentationAttributes(const SkSVGPresentationAttr
|
||||
ApplyLazyInheritedAttribute(StrokeMiterLimit);
|
||||
ApplyLazyInheritedAttribute(StrokeOpacity);
|
||||
ApplyLazyInheritedAttribute(StrokeWidth);
|
||||
ApplyLazyInheritedAttribute(TextAnchor);
|
||||
ApplyLazyInheritedAttribute(Visibility);
|
||||
ApplyLazyInheritedAttribute(Color);
|
||||
|
||||
|
@ -16,22 +16,6 @@
|
||||
|
||||
SkSVGText::SkSVGText() : INHERITED(SkSVGTag::kText) {}
|
||||
|
||||
void SkSVGText::setX(const SkSVGLength& x) { fX = x; }
|
||||
|
||||
void SkSVGText::setY(const SkSVGLength& y) { fY = y; }
|
||||
|
||||
void SkSVGText::setText(const SkSVGStringType& text) { fText = text; }
|
||||
|
||||
void SkSVGText::setTextAnchor(const SkSVGStringType& text_anchor) {
|
||||
if (strcmp(text_anchor.c_str(), "start") == 0) {
|
||||
fTextAlign = SkTextUtils::Align::kLeft_Align;
|
||||
} else if (strcmp(text_anchor.c_str(), "middle") == 0) {
|
||||
fTextAlign = SkTextUtils::Align::kCenter_Align;
|
||||
} else if (strcmp(text_anchor.c_str(), "end") == 0) {
|
||||
fTextAlign = SkTextUtils::Align::kRight_Align;
|
||||
}
|
||||
}
|
||||
|
||||
SkFont SkSVGText::resolveFont(const SkSVGRenderContext& ctx) const {
|
||||
auto weight = [](const SkSVGFontWeight& w) {
|
||||
switch (w.type()) {
|
||||
@ -92,14 +76,27 @@ SkFont SkSVGText::resolveFont(const SkSVGRenderContext& ctx) const {
|
||||
void SkSVGText::onRender(const SkSVGRenderContext& ctx) const {
|
||||
const auto font = this->resolveFont(ctx);
|
||||
|
||||
const auto text_align = [](const SkSVGTextAnchor& anchor) {
|
||||
switch (anchor.type()) {
|
||||
case SkSVGTextAnchor::Type::kStart : return SkTextUtils::Align::kLeft_Align;
|
||||
case SkSVGTextAnchor::Type::kMiddle: return SkTextUtils::Align::kCenter_Align;
|
||||
case SkSVGTextAnchor::Type::kEnd : return SkTextUtils::Align::kRight_Align;
|
||||
case SkSVGTextAnchor::Type::kInherit:
|
||||
SkASSERT(false);
|
||||
return SkTextUtils::Align::kLeft_Align;
|
||||
}
|
||||
SkUNREACHABLE;
|
||||
};
|
||||
|
||||
const auto align = text_align(*ctx.presentationContext().fInherited.fTextAnchor);
|
||||
if (const SkPaint* fillPaint = ctx.fillPaint()) {
|
||||
SkTextUtils::DrawString(ctx.canvas(), fText.c_str(), fX.value(), fY.value(), font,
|
||||
*fillPaint, fTextAlign);
|
||||
*fillPaint, align);
|
||||
}
|
||||
|
||||
if (const SkPaint* strokePaint = ctx.strokePaint()) {
|
||||
SkTextUtils::DrawString(ctx.canvas(), fText.c_str(), fX.value(), fY.value(), font,
|
||||
*strokePaint, fTextAlign);
|
||||
*strokePaint, align);
|
||||
}
|
||||
}
|
||||
|
||||
@ -129,12 +126,6 @@ void SkSVGText::onSetAttribute(SkSVGAttribute attr, const SkSVGValue& v) {
|
||||
this->setText(*text);
|
||||
}
|
||||
break;
|
||||
case SkSVGAttribute::kTextAnchor:
|
||||
if (const auto* text_anchor = v.as<SkSVGStringValue>()) {
|
||||
this->setTextAnchor(*text_anchor);
|
||||
}
|
||||
break;
|
||||
break;
|
||||
default:
|
||||
this->INHERITED::onSetAttribute(attr, v);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user