706 lines
21 KiB
C++
706 lines
21 KiB
C++
#include "svgproperty.h"
|
|
#include "svgelement.h"
|
|
#include "svgparserutils.h"
|
|
|
|
#include <cassert>
|
|
|
|
namespace lunasvg {
|
|
|
|
PropertyID propertyid(std::string_view name)
|
|
{
|
|
static const struct {
|
|
std::string_view name;
|
|
PropertyID value;
|
|
} table[] = {
|
|
{"class", PropertyID::Class},
|
|
{"clipPathUnits", PropertyID::ClipPathUnits},
|
|
{"cx", PropertyID::Cx},
|
|
{"cy", PropertyID::Cy},
|
|
{"d", PropertyID::D},
|
|
{"dx", PropertyID::Dx},
|
|
{"dy", PropertyID::Dy},
|
|
{"fx", PropertyID::Fx},
|
|
{"fy", PropertyID::Fy},
|
|
{"gradientTransform", PropertyID::GradientTransform},
|
|
{"gradientUnits", PropertyID::GradientUnits},
|
|
{"height", PropertyID::Height},
|
|
{"href", PropertyID::Href},
|
|
{"id", PropertyID::Id},
|
|
{"lengthAdjust", PropertyID::LengthAdjust},
|
|
{"markerHeight", PropertyID::MarkerHeight},
|
|
{"markerUnits", PropertyID::MarkerUnits},
|
|
{"markerWidth", PropertyID::MarkerWidth},
|
|
{"maskContentUnits", PropertyID::MaskContentUnits},
|
|
{"maskUnits", PropertyID::MaskUnits},
|
|
{"offset", PropertyID::Offset},
|
|
{"orient", PropertyID::Orient},
|
|
{"patternContentUnits", PropertyID::PatternContentUnits},
|
|
{"patternTransform", PropertyID::PatternTransform},
|
|
{"patternUnits", PropertyID::PatternUnits},
|
|
{"points", PropertyID::Points},
|
|
{"preserveAspectRatio", PropertyID::PreserveAspectRatio},
|
|
{"r", PropertyID::R},
|
|
{"refX", PropertyID::RefX},
|
|
{"refY", PropertyID::RefY},
|
|
{"rotate", PropertyID::Rotate},
|
|
{"rx", PropertyID::Rx},
|
|
{"ry", PropertyID::Ry},
|
|
{"spreadMethod", PropertyID::SpreadMethod},
|
|
{"style", PropertyID::Style},
|
|
{"textLength", PropertyID::TextLength},
|
|
{"transform", PropertyID::Transform},
|
|
{"viewBox", PropertyID::ViewBox},
|
|
{"width", PropertyID::Width},
|
|
{"x", PropertyID::X},
|
|
{"x1", PropertyID::X1},
|
|
{"x2", PropertyID::X2},
|
|
{"xlink:href", PropertyID::Href},
|
|
{"xml:space", PropertyID::White_Space},
|
|
{"y", PropertyID::Y},
|
|
{"y1", PropertyID::Y1},
|
|
{"y2", PropertyID::Y2}
|
|
};
|
|
|
|
auto it = std::lower_bound(table, std::end(table), name, [](const auto& item, const auto& name) { return item.name < name; });
|
|
if(it == std::end(table) || it->name != name)
|
|
return csspropertyid(name);
|
|
return it->value;
|
|
}
|
|
|
|
PropertyID csspropertyid(std::string_view name)
|
|
{
|
|
static const struct {
|
|
std::string_view name;
|
|
PropertyID value;
|
|
} table[] = {
|
|
{"alignment-baseline", PropertyID::Alignment_Baseline},
|
|
{"baseline-shift", PropertyID::Baseline_Shift},
|
|
{"clip-path", PropertyID::Clip_Path},
|
|
{"clip-rule", PropertyID::Clip_Rule},
|
|
{"color", PropertyID::Color},
|
|
{"direction", PropertyID::Direction},
|
|
{"display", PropertyID::Display},
|
|
{"dominant-baseline", PropertyID::Dominant_Baseline},
|
|
{"fill", PropertyID::Fill},
|
|
{"fill-opacity", PropertyID::Fill_Opacity},
|
|
{"fill-rule", PropertyID::Fill_Rule},
|
|
{"font-family", PropertyID::Font_Family},
|
|
{"font-size", PropertyID::Font_Size},
|
|
{"font-style", PropertyID::Font_Style},
|
|
{"font-weight", PropertyID::Font_Weight},
|
|
{"letter-spacing", PropertyID::Letter_Spacing},
|
|
{"marker-end", PropertyID::Marker_End},
|
|
{"marker-mid", PropertyID::Marker_Mid},
|
|
{"marker-start", PropertyID::Marker_Start},
|
|
{"mask", PropertyID::Mask},
|
|
{"mask-type", PropertyID::Mask_Type},
|
|
{"opacity", PropertyID::Opacity},
|
|
{"overflow", PropertyID::Overflow},
|
|
{"pointer-events", PropertyID::Pointer_Events},
|
|
{"stop-color", PropertyID::Stop_Color},
|
|
{"stop-opacity", PropertyID::Stop_Opacity},
|
|
{"stroke", PropertyID::Stroke},
|
|
{"stroke-dasharray", PropertyID::Stroke_Dasharray},
|
|
{"stroke-dashoffset", PropertyID::Stroke_Dashoffset},
|
|
{"stroke-linecap", PropertyID::Stroke_Linecap},
|
|
{"stroke-linejoin", PropertyID::Stroke_Linejoin},
|
|
{"stroke-miterlimit", PropertyID::Stroke_Miterlimit},
|
|
{"stroke-opacity", PropertyID::Stroke_Opacity},
|
|
{"stroke-width", PropertyID::Stroke_Width},
|
|
{"text-anchor", PropertyID::Text_Anchor},
|
|
{"text-orientation", PropertyID::Text_Orientation},
|
|
{"visibility", PropertyID::Visibility},
|
|
{"white-space", PropertyID::White_Space},
|
|
{"word-spacing", PropertyID::Word_Spacing},
|
|
{"writing-mode", PropertyID::Writing_Mode}
|
|
};
|
|
|
|
auto it = std::lower_bound(table, std::end(table), name, [](const auto& item, const auto& name) { return item.name < name; });
|
|
if(it == std::end(table) || it->name != name)
|
|
return PropertyID::Unknown;
|
|
return it->value;
|
|
}
|
|
|
|
SVGProperty::SVGProperty(PropertyID id)
|
|
: m_id(id)
|
|
{
|
|
}
|
|
|
|
bool SVGString::parse(std::string_view input)
|
|
{
|
|
stripLeadingAndTrailingSpaces(input);
|
|
m_value.assign(input);
|
|
return true;
|
|
}
|
|
|
|
template<>
|
|
bool SVGEnumeration<SpreadMethod>::parse(std::string_view input)
|
|
{
|
|
static const SVGEnumerationEntry<SpreadMethod> entries[] = {
|
|
{SpreadMethod::Pad, "pad"},
|
|
{SpreadMethod::Reflect, "reflect"},
|
|
{SpreadMethod::Repeat, "repeat"}
|
|
};
|
|
|
|
return parseEnum(input, entries);
|
|
}
|
|
|
|
template<>
|
|
bool SVGEnumeration<Units>::parse(std::string_view input)
|
|
{
|
|
static const SVGEnumerationEntry<Units> entries[] = {
|
|
{Units::UserSpaceOnUse, "userSpaceOnUse"},
|
|
{Units::ObjectBoundingBox, "objectBoundingBox"}
|
|
};
|
|
|
|
return parseEnum(input, entries);
|
|
}
|
|
|
|
template<>
|
|
bool SVGEnumeration<MarkerUnits>::parse(std::string_view input)
|
|
{
|
|
static const SVGEnumerationEntry<MarkerUnits> entries[] = {
|
|
{MarkerUnits::StrokeWidth, "strokeWidth"},
|
|
{MarkerUnits::UserSpaceOnUse, "userSpaceOnUse"}
|
|
};
|
|
|
|
return parseEnum(input, entries);
|
|
}
|
|
|
|
template<>
|
|
bool SVGEnumeration<LengthAdjust>::parse(std::string_view input)
|
|
{
|
|
static const SVGEnumerationEntry<LengthAdjust> entries[] = {
|
|
{LengthAdjust::Spacing, "spacing"},
|
|
{LengthAdjust::SpacingAndGlyphs, "spacingAndGlyphs"}
|
|
};
|
|
|
|
return parseEnum(input, entries);
|
|
}
|
|
|
|
template<typename Enum>
|
|
template<unsigned int N>
|
|
bool SVGEnumeration<Enum>::parseEnum(std::string_view input, const SVGEnumerationEntry<Enum>(&entries)[N])
|
|
{
|
|
stripLeadingAndTrailingSpaces(input);
|
|
for(const auto& entry : entries) {
|
|
if(input == entry.second) {
|
|
m_value = entry.first;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool SVGAngle::parse(std::string_view input)
|
|
{
|
|
stripLeadingAndTrailingSpaces(input);
|
|
if(input == "auto") {
|
|
m_value = 0.f;
|
|
m_orientType = OrientType::Auto;
|
|
return true;
|
|
}
|
|
|
|
if(input == "auto-start-reverse") {
|
|
m_value = 0.f;
|
|
m_orientType = OrientType::AutoStartReverse;
|
|
return true;
|
|
}
|
|
|
|
float value = 0.f;
|
|
if(!parseNumber(input, value))
|
|
return false;
|
|
if(!input.empty()) {
|
|
if(input == "rad")
|
|
value *= 180.f / PLUTOVG_PI;
|
|
else if(input == "grad")
|
|
value *= 360.f / 400.f;
|
|
else if(input == "turn")
|
|
value *= 360.f;
|
|
else if(input != "deg") {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
m_value = value;
|
|
m_orientType = OrientType::Angle;
|
|
return true;
|
|
}
|
|
|
|
bool Length::parse(std::string_view input, LengthNegativeMode mode)
|
|
{
|
|
float value = 0.f;
|
|
stripLeadingAndTrailingSpaces(input);
|
|
if(!parseNumber(input, value))
|
|
return false;
|
|
if(value < 0.f && mode == LengthNegativeMode::Forbid)
|
|
return false;
|
|
if(input.empty()) {
|
|
m_value = value;
|
|
m_units = LengthUnits::None;
|
|
return true;
|
|
}
|
|
|
|
constexpr auto dpi = 96.f;
|
|
switch(input.front()) {
|
|
case '%':
|
|
m_value = value;
|
|
m_units = LengthUnits::Percent;
|
|
input.remove_prefix(1);
|
|
break;
|
|
case 'p':
|
|
input.remove_prefix(1);
|
|
if(input.empty())
|
|
return false;
|
|
else if(input.front() == 'x')
|
|
m_value = value;
|
|
else if(input.front() == 'c')
|
|
m_value = value * dpi / 6.f;
|
|
else if(input.front() == 't')
|
|
m_value = value * dpi / 72.f;
|
|
else
|
|
return false;
|
|
m_units = LengthUnits::Px;
|
|
input.remove_prefix(1);
|
|
break;
|
|
case 'i':
|
|
input.remove_prefix(1);
|
|
if(input.empty())
|
|
return false;
|
|
else if(input.front() == 'n')
|
|
m_value = value * dpi;
|
|
else
|
|
return false;
|
|
m_units = LengthUnits::Px;
|
|
input.remove_prefix(1);
|
|
break;
|
|
case 'c':
|
|
input.remove_prefix(1);
|
|
if(input.empty())
|
|
return false;
|
|
else if(input.front() == 'm')
|
|
m_value = value * dpi / 2.54f;
|
|
else
|
|
return false;
|
|
m_units = LengthUnits::Px;
|
|
input.remove_prefix(1);
|
|
break;
|
|
case 'm':
|
|
input.remove_prefix(1);
|
|
if(input.empty())
|
|
return false;
|
|
else if(input.front() == 'm')
|
|
m_value = value * dpi / 25.4f;
|
|
else
|
|
return false;
|
|
m_units = LengthUnits::Px;
|
|
input.remove_prefix(1);
|
|
break;
|
|
case 'e':
|
|
input.remove_prefix(1);
|
|
if(input.empty())
|
|
return false;
|
|
else if(input.front() == 'm')
|
|
m_units = LengthUnits::Em;
|
|
else if(input.front() == 'x')
|
|
m_units = LengthUnits::Ex;
|
|
else
|
|
return false;
|
|
m_value = value;
|
|
input.remove_prefix(1);
|
|
break;
|
|
default:
|
|
return false;
|
|
}
|
|
|
|
return input.empty();
|
|
}
|
|
|
|
float LengthContext::valueForLength(const Length& length, LengthDirection direction) const
|
|
{
|
|
if(length.units() == LengthUnits::Percent) {
|
|
if(m_units == Units::UserSpaceOnUse)
|
|
return length.value() * viewportDimension(direction) / 100.f;
|
|
return length.value() / 100.f;
|
|
}
|
|
|
|
if(length.units() == LengthUnits::Ex)
|
|
return length.value() * m_element->font_size() / 2.f;
|
|
if(length.units() == LengthUnits::Em)
|
|
return length.value() * m_element->font_size();
|
|
return length.value();
|
|
}
|
|
|
|
float LengthContext::viewportDimension(LengthDirection direction) const
|
|
{
|
|
auto viewportSize = m_element->currentViewportSize();
|
|
switch(direction) {
|
|
case LengthDirection::Horizontal:
|
|
return viewportSize.w;
|
|
case LengthDirection::Vertical:
|
|
return viewportSize.h;
|
|
default:
|
|
return std::sqrt(viewportSize.w * viewportSize.w + viewportSize.h * viewportSize.h) / PLUTOVG_SQRT2;
|
|
}
|
|
}
|
|
|
|
bool SVGLength::parse(std::string_view input)
|
|
{
|
|
return m_value.parse(input, m_negativeMode);
|
|
}
|
|
|
|
bool SVGLengthList::parse(std::string_view input)
|
|
{
|
|
m_values.clear();
|
|
while(!input.empty()) {
|
|
size_t count = 0;
|
|
while(count < input.length() && input[count] != ',' && !IS_WS(input[count]))
|
|
++count;
|
|
if(count == 0)
|
|
break;
|
|
Length value(0, LengthUnits::None);
|
|
if(!value.parse(input.substr(0, count), m_negativeMode))
|
|
return false;
|
|
input.remove_prefix(count);
|
|
skipOptionalSpacesOrComma(input);
|
|
m_values.push_back(value);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool SVGNumber::parse(std::string_view input)
|
|
{
|
|
float value = 0.f;
|
|
stripLeadingAndTrailingSpaces(input);
|
|
if(!parseNumber(input, value))
|
|
return false;
|
|
if(!input.empty())
|
|
return false;
|
|
m_value = value;
|
|
return true;
|
|
}
|
|
|
|
bool SVGNumberPercentage::parse(std::string_view input)
|
|
{
|
|
float value = 0.f;
|
|
stripLeadingAndTrailingSpaces(input);
|
|
if(!parseNumber(input, value))
|
|
return false;
|
|
if(!input.empty() && input.front() == '%') {
|
|
value /= 100.f;
|
|
input.remove_prefix(1);
|
|
}
|
|
|
|
if(!input.empty())
|
|
return false;
|
|
m_value = std::clamp(value, 0.f, 1.f);
|
|
return true;
|
|
}
|
|
|
|
bool SVGNumberList::parse(std::string_view input)
|
|
{
|
|
m_values.clear();
|
|
stripLeadingSpaces(input);
|
|
while(!input.empty()) {
|
|
float value = 0.f;
|
|
if(!parseNumber(input, value))
|
|
return false;
|
|
skipOptionalSpacesOrComma(input);
|
|
m_values.push_back(value);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool SVGPath::parse(std::string_view input)
|
|
{
|
|
return m_value.parse(input.data(), input.length());
|
|
}
|
|
|
|
bool SVGPoint::parse(std::string_view input)
|
|
{
|
|
Point value;
|
|
stripLeadingAndTrailingSpaces(input);
|
|
if(!parseNumber(input, value.x)
|
|
|| !skipOptionalSpaces(input)
|
|
|| !parseNumber(input, value.y)
|
|
|| !input.empty()) {
|
|
return false;
|
|
}
|
|
|
|
m_value = value;
|
|
return true;
|
|
}
|
|
|
|
bool SVGPointList::parse(std::string_view input)
|
|
{
|
|
m_values.clear();
|
|
stripLeadingSpaces(input);
|
|
while(!input.empty()) {
|
|
Point value;
|
|
if(!parseNumber(input, value.x)
|
|
|| !skipOptionalSpacesOrComma(input)
|
|
|| !parseNumber(input, value.y)) {
|
|
return false;
|
|
}
|
|
|
|
m_values.push_back(value);
|
|
skipOptionalSpacesOrComma(input);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool SVGRect::parse(std::string_view input)
|
|
{
|
|
Rect value;
|
|
stripLeadingAndTrailingSpaces(input);
|
|
if(!parseNumber(input, value.x)
|
|
|| !skipOptionalSpacesOrComma(input)
|
|
|| !parseNumber(input, value.y)
|
|
|| !skipOptionalSpacesOrComma(input)
|
|
|| !parseNumber(input, value.w)
|
|
|| !skipOptionalSpacesOrComma(input)
|
|
|| !parseNumber(input, value.h)
|
|
|| !input.empty()) {
|
|
return false;
|
|
}
|
|
|
|
if(value.w < 0.f || value.h < 0.f)
|
|
return false;
|
|
m_value = value;
|
|
return true;
|
|
}
|
|
|
|
bool SVGTransform::parse(std::string_view input)
|
|
{
|
|
return m_value.parse(input.data(), input.length());
|
|
}
|
|
|
|
bool SVGPreserveAspectRatio::parse(std::string_view input)
|
|
{
|
|
auto alignType = AlignType::xMidYMid;
|
|
stripLeadingSpaces(input);
|
|
if(skipString(input, "none"))
|
|
alignType = AlignType::None;
|
|
else if(skipString(input, "xMinYMin"))
|
|
alignType = AlignType::xMinYMin;
|
|
else if(skipString(input, "xMidYMin"))
|
|
alignType = AlignType::xMidYMin;
|
|
else if(skipString(input, "xMaxYMin"))
|
|
alignType = AlignType::xMaxYMin;
|
|
else if(skipString(input, "xMinYMid"))
|
|
alignType = AlignType::xMinYMid;
|
|
else if(skipString(input, "xMidYMid"))
|
|
alignType = AlignType::xMidYMid;
|
|
else if(skipString(input, "xMaxYMid"))
|
|
alignType = AlignType::xMaxYMid;
|
|
else if(skipString(input, "xMinYMax"))
|
|
alignType = AlignType::xMinYMax;
|
|
else if(skipString(input, "xMidYMax"))
|
|
alignType = AlignType::xMidYMax;
|
|
else if(skipString(input, "xMaxYMax"))
|
|
alignType = AlignType::xMaxYMax;
|
|
else {
|
|
return false;
|
|
}
|
|
|
|
auto meetOrSlice = MeetOrSlice::Meet;
|
|
skipOptionalSpaces(input);
|
|
if(skipString(input, "meet")) {
|
|
meetOrSlice = MeetOrSlice::Meet;
|
|
} else if(skipString(input, "slice")) {
|
|
meetOrSlice = MeetOrSlice::Slice;
|
|
}
|
|
|
|
if(alignType == AlignType::None)
|
|
meetOrSlice = MeetOrSlice::Meet;
|
|
skipOptionalSpaces(input);
|
|
if(!input.empty())
|
|
return false;
|
|
m_alignType = alignType;
|
|
m_meetOrSlice = meetOrSlice;
|
|
return true;
|
|
}
|
|
|
|
Rect SVGPreserveAspectRatio::getClipRect(const Rect& viewBoxRect, const Size& viewportSize) const
|
|
{
|
|
assert(!viewBoxRect.isEmpty() && !viewportSize.isEmpty());
|
|
auto xScale = viewportSize.w / viewBoxRect.w;
|
|
auto yScale = viewportSize.h / viewBoxRect.h;
|
|
if(m_alignType == AlignType::None) {
|
|
return Rect(viewBoxRect.x, viewBoxRect.y, viewportSize.w / xScale, viewportSize.h / yScale);
|
|
}
|
|
|
|
auto scale = (m_meetOrSlice == MeetOrSlice::Meet) ? std::min(xScale, yScale) : std::max(xScale, yScale);
|
|
auto xOffset = -viewBoxRect.x * scale;
|
|
auto yOffset = -viewBoxRect.y * scale;
|
|
auto viewWidth = viewBoxRect.w * scale;
|
|
auto viewHeight = viewBoxRect.h * scale;
|
|
switch(m_alignType) {
|
|
case AlignType::xMidYMin:
|
|
case AlignType::xMidYMid:
|
|
case AlignType::xMidYMax:
|
|
xOffset += (viewportSize.w - viewWidth) * 0.5f;
|
|
break;
|
|
case AlignType::xMaxYMin:
|
|
case AlignType::xMaxYMid:
|
|
case AlignType::xMaxYMax:
|
|
xOffset += (viewportSize.w - viewWidth);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
switch(m_alignType) {
|
|
case AlignType::xMinYMid:
|
|
case AlignType::xMidYMid:
|
|
case AlignType::xMaxYMid:
|
|
yOffset += (viewportSize.h - viewHeight) * 0.5f;
|
|
break;
|
|
case AlignType::xMinYMax:
|
|
case AlignType::xMidYMax:
|
|
case AlignType::xMaxYMax:
|
|
yOffset += (viewportSize.h - viewHeight);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return Rect(-xOffset / scale, -yOffset / scale, viewportSize.w / scale, viewportSize.h / scale);
|
|
}
|
|
|
|
Transform SVGPreserveAspectRatio::getTransform(const Rect& viewBoxRect, const Size& viewportSize) const
|
|
{
|
|
assert(!viewBoxRect.isEmpty() && !viewportSize.isEmpty());
|
|
auto xScale = viewportSize.w / viewBoxRect.w;
|
|
auto yScale = viewportSize.h / viewBoxRect.h;
|
|
if(m_alignType == AlignType::None) {
|
|
return Transform(xScale, 0, 0, yScale, -viewBoxRect.x * xScale, -viewBoxRect.y * yScale);
|
|
}
|
|
|
|
auto scale = (m_meetOrSlice == MeetOrSlice::Meet) ? std::min(xScale, yScale) : std::max(xScale, yScale);
|
|
auto xOffset = -viewBoxRect.x * scale;
|
|
auto yOffset = -viewBoxRect.y * scale;
|
|
auto viewWidth = viewBoxRect.w * scale;
|
|
auto viewHeight = viewBoxRect.h * scale;
|
|
switch(m_alignType) {
|
|
case AlignType::xMidYMin:
|
|
case AlignType::xMidYMid:
|
|
case AlignType::xMidYMax:
|
|
xOffset += (viewportSize.w - viewWidth) * 0.5f;
|
|
break;
|
|
case AlignType::xMaxYMin:
|
|
case AlignType::xMaxYMid:
|
|
case AlignType::xMaxYMax:
|
|
xOffset += (viewportSize.w - viewWidth);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
switch(m_alignType) {
|
|
case AlignType::xMinYMid:
|
|
case AlignType::xMidYMid:
|
|
case AlignType::xMaxYMid:
|
|
yOffset += (viewportSize.h - viewHeight) * 0.5f;
|
|
break;
|
|
case AlignType::xMinYMax:
|
|
case AlignType::xMidYMax:
|
|
case AlignType::xMaxYMax:
|
|
yOffset += (viewportSize.h - viewHeight);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return Transform(scale, 0, 0, scale, xOffset, yOffset);
|
|
}
|
|
|
|
void SVGPreserveAspectRatio::transformRect(Rect& dstRect, Rect& srcRect) const
|
|
{
|
|
if(m_alignType == AlignType::None)
|
|
return;
|
|
auto viewSize = dstRect.size();
|
|
auto imageSize = srcRect.size();
|
|
if(m_meetOrSlice == MeetOrSlice::Meet) {
|
|
auto scale = imageSize.h / imageSize.w;
|
|
if(viewSize.h > viewSize.w * scale) {
|
|
dstRect.h = viewSize.w * scale;
|
|
switch(m_alignType) {
|
|
case AlignType::xMinYMid:
|
|
case AlignType::xMidYMid:
|
|
case AlignType::xMaxYMid:
|
|
dstRect.y += (viewSize.h - dstRect.h) * 0.5f;
|
|
break;
|
|
case AlignType::xMinYMax:
|
|
case AlignType::xMidYMax:
|
|
case AlignType::xMaxYMax:
|
|
dstRect.y += viewSize.h - dstRect.h;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(viewSize.w > viewSize.h / scale) {
|
|
dstRect.w = viewSize.h / scale;
|
|
switch(m_alignType) {
|
|
case AlignType::xMidYMin:
|
|
case AlignType::xMidYMid:
|
|
case AlignType::xMidYMax:
|
|
dstRect.x += (viewSize.w - dstRect.w) * 0.5f;
|
|
break;
|
|
case AlignType::xMaxYMin:
|
|
case AlignType::xMaxYMid:
|
|
case AlignType::xMaxYMax:
|
|
dstRect.x += viewSize.w - dstRect.w;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
} else if(m_meetOrSlice == MeetOrSlice::Slice) {
|
|
auto scale = imageSize.h / imageSize.w;
|
|
if(viewSize.h < viewSize.w * scale) {
|
|
srcRect.h = viewSize.h * (imageSize.w / viewSize.w);
|
|
switch(m_alignType) {
|
|
case AlignType::xMinYMid:
|
|
case AlignType::xMidYMid:
|
|
case AlignType::xMaxYMid:
|
|
srcRect.y += (imageSize.h - srcRect.h) * 0.5f;
|
|
break;
|
|
case AlignType::xMinYMax:
|
|
case AlignType::xMidYMax:
|
|
case AlignType::xMaxYMax:
|
|
srcRect.y += imageSize.h - srcRect.h;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(viewSize.w < viewSize.h / scale) {
|
|
srcRect.w = viewSize.w * (imageSize.h / viewSize.h);
|
|
switch(m_alignType) {
|
|
case AlignType::xMidYMin:
|
|
case AlignType::xMidYMid:
|
|
case AlignType::xMidYMax:
|
|
srcRect.x += (imageSize.w - srcRect.w) * 0.5f;
|
|
break;
|
|
case AlignType::xMaxYMin:
|
|
case AlignType::xMaxYMid:
|
|
case AlignType::xMaxYMax:
|
|
srcRect.x += imageSize.w - srcRect.w;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
} // namespace lunasvg
|