[DEV] add support of radial gradient (partial)

This commit is contained in:
Edouard DUPIN 2015-12-21 21:01:20 +01:00
parent 8610d6491b
commit dbbd996850
7 changed files with 394 additions and 70 deletions

View File

@ -67,7 +67,8 @@ void esvg::Dimension::set(std::string _config) {
type = esvg::distance_meter;
_config.erase(_config.size()-1, 1);
} else {
ESVG_CRITICAL("Can not parse dimention : \"" << _config << "\"");
type = esvg::distance_pixel;
ESVG_VERBOSE("default dimention type for: '" << _config << "' ==> pixel");
return;
}
vec2 tmp = _config;
@ -326,8 +327,8 @@ void esvg::Dimension1D::set(std::string _config) {
type = esvg::distance_meter;
_config.erase(_config.size()-1, 1);
} else {
ESVG_CRITICAL("Can not parse dimention : \"" << _config << "\"");
return;
type = esvg::distance_pixel;
ESVG_VERBOSE("default dimention type for: '" << _config << "' ==> pixel");
}
float tmp = etk::string_to_float(_config);
set(tmp, type);

View File

@ -105,7 +105,7 @@ void esvg::Renderer::print(const esvg::render::Weight& _weightFill,
}
#ifdef DEBUG
// display the gradient position:
std::shared_ptr<esvg::render::DynamicColorLinear> tmpColor = std::dynamic_pointer_cast<esvg::render::DynamicColorLinear>(_colorFill);
std::shared_ptr<esvg::render::DynamicColorSpecial> tmpColor = std::dynamic_pointer_cast<esvg::render::DynamicColorSpecial>(_colorFill);
if (tmpColor != nullptr) {
esvg::render::SegmentList listSegment;
// Display bounding box

View File

@ -291,7 +291,7 @@ bool esvg::Document::parseXMLData(const std::shared_ptr<exml::Element>& _root, b
ESVG_ERROR("'" << child->getValue() << "' node must not be defined outside a defs Section");
continue;
} else {
//elementParser = std::make_shared<esvg::RadialGradient>(m_paint);
elementParser = std::make_shared<esvg::RadialGradient>(m_paint);
}
} else if (child->getValue() == "linearGradient") {
if (_isReference == false) {

View File

@ -9,19 +9,21 @@
#include <esvg/debug.h>
#include <esvg/render/DynamicColor.h>
#include <esvg/LinearGradient.h>
#include <esvg/RadialGradient.h>
#include <esvg/esvg.h>
#undef __class__
#define __class__ "render:DynamicColorLinear"
#define __class__ "render:DynamicColorSpecial"
esvg::render::DynamicColorLinear::DynamicColorLinear(const std::string& _link, const mat2& _mtx) :
esvg::render::DynamicColorSpecial::DynamicColorSpecial(const std::string& _link, const mat2& _mtx) :
m_linear(true),
m_colorName(_link),
m_matrix(_mtx),
m_viewPort(vec2(9999999999.0,9999999999.0),vec2(-9999999999.0,-9999999999.0)) {
}
void esvg::render::DynamicColorLinear::setViewPort(const std::pair<vec2, vec2>& _viewPort) {
void esvg::render::DynamicColorSpecial::setViewPort(const std::pair<vec2, vec2>& _viewPort) {
m_viewPort = _viewPort;
}
@ -43,11 +45,19 @@ static vec2 getIntersect(const vec2& _point1,
return _point2;
}
// TODO : This can optimize ... really slow ... and not linear
etk::Color<float,4> esvg::render::DynamicColorLinear::getColor(const ivec2& _pos) {
etk::Color<float,4> esvg::render::DynamicColorSpecial::getColor(const ivec2& _pos) {
if (m_data.size() < 2) {
return etk::color::purple;
}
if (m_linear == true) {
return getColorLinear(_pos);
} else {
return getColorRadial(_pos);
}
return etk::color::purple;
}
etk::Color<float,4> esvg::render::DynamicColorSpecial::getColorLinear(const ivec2& _pos) {
float ratio = 0.0f;
if (m_unit == gradientUnits_userSpaceOnUse) {
vec2 vectorBase = m_pos2 - m_pos1;
@ -146,7 +156,73 @@ etk::Color<float,4> esvg::render::DynamicColorLinear::getColor(const ivec2& _pos
return etk::color::green;
}
void esvg::render::DynamicColorLinear::generate(esvg::Document* _document) {
etk::Color<float,4> esvg::render::DynamicColorSpecial::getColorRadial(const ivec2& _pos) {
float ratio = 0.0f;
// in the basic vertion of the gradient the color is calculated with the ration in X and Y in the bonding box associated (it is rotate with the object..
vec2 intersecX = getIntersect(m_pos1, m_axeX,
vec2(_pos.x(), _pos.y()), m_axeY);
vec2 intersecY = getIntersect(m_pos1, m_axeY,
vec2(_pos.x(), _pos.y()), m_axeX);
vec2 vectorBaseDrawX = intersecX - m_pos1;
vec2 vectorBaseDrawY = intersecY - m_pos1;
float baseDrawX = vectorBaseDrawX.length();
float baseDrawY = vectorBaseDrawY.length();
ratio = vec2(baseDrawX, baseDrawY).length();
if (m_baseSize.x()+m_baseSize.y() != 0.0f) {
ratio /= 100.0f;//(m_baseSize.x()*m_baseSize.y());
} else {
ratio = 1.0f;
}
if (m_baseSize.x()+m_baseSize.y() != 0.0f) {
if ( m_baseSize.x() != 0.0f
&& m_baseSize.y() != 0.0f) {
ratio = vec2(baseDrawX/m_baseSize.x(), baseDrawY/m_baseSize.y()).length();
} else if (m_baseSize.x() != 0.0f) {
ratio = baseDrawX/m_baseSize.x();
} else {
ratio = baseDrawY/m_baseSize.y();
}
} else {
ratio = 1.0f;
}
switch(m_spread) {
case spreadMethod_pad:
// nothing to do ...
break;
case spreadMethod_reflect:
ratio -= float((int32_t(ratio)>>1)<<1);
if (ratio > 1.0f) {
ratio = 2.0f-ratio;
}
break;
case spreadMethod_repeat:
ratio -= float(int32_t(ratio));
if (ratio <0.0f) {
ratio = 1.0f-std::abs(ratio);
}
break;
}
if (ratio <= m_data[0].first*0.01f) {
return m_data[0].second;
}
if (ratio >= m_data.back().first*0.01f) {
return m_data.back().second;
}
for (size_t iii=1; iii<m_data.size(); ++iii) {
if (ratio <= m_data[iii].first*0.01f) {
float localRatio = ratio - m_data[iii-1].first*0.01f;
localRatio = localRatio / ((m_data[iii].first - m_data[iii-1].first) * 0.01f);
return etk::Color<float,4>(m_data[iii-1].second.r() * (1.0-localRatio) + m_data[iii].second.r() * localRatio,
m_data[iii-1].second.g() * (1.0-localRatio) + m_data[iii].second.g() * localRatio,
m_data[iii-1].second.b() * (1.0-localRatio) + m_data[iii].second.b() * localRatio,
m_data[iii-1].second.a() * (1.0-localRatio) + m_data[iii].second.a() * localRatio);
}
}
return etk::color::green;
}
void esvg::render::DynamicColorSpecial::generate(esvg::Document* _document) {
if (_document == nullptr) {
ESVG_ERROR("Get nullptr input for document");
return;
@ -156,57 +232,117 @@ void esvg::render::DynamicColorLinear::generate(esvg::Document* _document) {
ESVG_ERROR("Can not get base : '" << m_colorName << "'");
return;
}
// Now we can know if we use linear or radial gradient ...
std::shared_ptr<esvg::LinearGradient> gradient = std::dynamic_pointer_cast<esvg::LinearGradient>(base);
if (gradient == nullptr) {
ESVG_ERROR("Can not cast in a linear gradient: '" << m_colorName << "' ==> wrong type");
return;
}
ESVG_INFO("get for color linear:");
gradient->display(2);
m_unit = gradient->m_unit;
m_spread = gradient->m_spread;
ESVG_INFO(" viewport = {" << m_viewPort.first << "," << m_viewPort.second << "}");
vec2 size = m_viewPort.second - m_viewPort.first;
esvg::Dimension dimPos1 = gradient->getPosition1();
m_pos1 = dimPos1.getPixel(size);
if (dimPos1.getType() == esvg::distance_pourcent) {
m_pos1 += m_viewPort.first;
}
esvg::Dimension dimPos2 = gradient->getPosition2();
m_pos2 = dimPos2.getPixel(size);
if (dimPos2.getType() == esvg::distance_pourcent) {
m_pos2 += m_viewPort.first;
}
// in the basic vertion of the gradient the color is calculated with the ration in X and Y in the bonding box associated (it is rotate with the object..
vec2 delta = m_pos2 - m_pos1;
if (delta.x() < 0.0f) {
m_axeX = vec2(-1.0f, 0.0f);
if (gradient != nullptr) {
m_linear = true;
ESVG_INFO("get for color linear:");
gradient->display(2);
m_unit = gradient->m_unit;
m_spread = gradient->m_spread;
ESVG_INFO(" viewport = {" << m_viewPort.first << "," << m_viewPort.second << "}");
vec2 size = m_viewPort.second - m_viewPort.first;
esvg::Dimension dimPos1 = gradient->getPosition1();
m_pos1 = dimPos1.getPixel(size);
if (dimPos1.getType() == esvg::distance_pourcent) {
m_pos1 += m_viewPort.first;
}
esvg::Dimension dimPos2 = gradient->getPosition2();
m_pos2 = dimPos2.getPixel(size);
if (dimPos2.getType() == esvg::distance_pourcent) {
m_pos2 += m_viewPort.first;
}
// in the basic vertion of the gradient the color is calculated with the ration in X and Y in the bonding box associated (it is rotate with the object..
vec2 delta = m_pos2 - m_pos1;
if (delta.x() < 0.0f) {
m_axeX = vec2(-1.0f, 0.0f);
} else {
m_axeX = vec2(1.0f, 0.0f);
}
if (delta.y() < 0.0f) {
m_axeY = vec2(0.0f, -1.0f);
} else {
m_axeY = vec2(0.0f, 1.0f);
}
// Move the positions ...
m_pos1 = m_matrix * m_pos1;
m_pos2 = m_matrix * m_pos2;
m_axeX = m_matrix.applyScaleRotation(m_axeX);
m_axeY = m_matrix.applyScaleRotation(m_axeY);
// in the basic vertion of the gradient the color is calculated with the ration in X and Y in the bonding box associated (it is rotate with the object..
vec2 intersecX = getIntersect(m_pos1, m_axeX,
m_pos2, m_axeY);
vec2 intersecY = getIntersect(m_pos1, m_axeY,
m_pos2, m_axeX);
m_baseSize = vec2((m_pos1 - intersecX).length(),
(m_pos1 - intersecY).length());
// get all the colors
m_data = gradient->getColors(_document);
} else {
m_axeX = vec2(1.0f, 0.0f);
m_linear = false;
std::shared_ptr<esvg::RadialGradient> gradient = std::dynamic_pointer_cast<esvg::RadialGradient>(base);
if (gradient == nullptr) {
ESVG_ERROR("Can not cast in a linear gradient: '" << m_colorName << "' ==> wrong type");
return;
}
ESVG_INFO("get for color Radial:");
gradient->display(2);
m_unit = gradient->m_unit;
m_spread = gradient->m_spread;
ESVG_INFO(" viewport = {" << m_viewPort.first << "," << m_viewPort.second << "}");
vec2 size = m_viewPort.second - m_viewPort.first;
esvg::Dimension dimCenter = gradient->getCenter();
m_pos1 = dimCenter.getPixel(size);
if (dimCenter.getType() == esvg::distance_pourcent) {
m_pos1 += m_viewPort.first;
}
esvg::Dimension dimFocal = gradient->getFocal();
m_focal = dimFocal.getPixel(size);
if (dimFocal.getType() == esvg::distance_pourcent) {
m_focal += m_viewPort.first;
}
esvg::Dimension1D dimRadius = gradient->getRadius();
m_pos2.setX(dimRadius.getPixel(size.x()));
m_pos2.setY(dimRadius.getPixel(size.y()));
m_pos2 += m_pos1;
/*
if (dimRadius.getType() == esvg::distance_pourcent) {
m_pos2 += m_viewPort.first;
}
*/
// in the basic vertion of the gradient the color is calculated with the ration in X and Y in the bonding box associated (it is rotate with the object..
vec2 delta = m_pos1 - m_pos2;
if (delta.x() < 0.0f) {
m_axeX = vec2(-1.0f, 0.0f);
} else {
m_axeX = vec2(1.0f, 0.0f);
}
if (delta.y() < 0.0f) {
m_axeY = vec2(0.0f, -1.0f);
} else {
m_axeY = vec2(0.0f, 1.0f);
}
// Move the positions ...
m_pos1 = m_matrix * m_pos1;
m_focal = m_matrix * m_focal;
m_pos2 = m_matrix * m_pos2;
m_axeX = m_matrix.applyScaleRotation(m_axeX);
m_axeY = m_matrix.applyScaleRotation(m_axeY);
// in the basic vertion of the gradient the color is calculated with the ration in X and Y in the bonding box associated (it is rotate with the object..
vec2 intersecX = getIntersect(m_pos1, m_axeX,
m_pos2, m_axeY);
vec2 intersecY = getIntersect(m_pos1, m_axeY,
m_pos2, m_axeX);
m_baseSize = vec2((m_pos1 - intersecX).length(),
(m_pos1 - intersecY).length());
ESVG_VERBOSE("baseSize=" << m_baseSize << " m_pos1=" << m_pos1 << " dim=" << dimCenter << " m_focal=" << m_focal << " m_pos2=" << m_pos2 << " dim=" << dimRadius);
// get all the colors
m_data = gradient->getColors(_document);
}
if (delta.y() < 0.0f) {
m_axeY = vec2(0.0f, -1.0f);
} else {
m_axeY = vec2(0.0f, 1.0f);
}
// Move the positions ...
m_pos1 = m_matrix * m_pos1;
m_pos2 = m_matrix * m_pos2;
m_axeX = m_matrix.applyScaleRotation(m_axeX);
m_axeY = m_matrix.applyScaleRotation(m_axeY);
// in the basic vertion of the gradient the color is calculated with the ration in X and Y in the bonding box associated (it is rotate with the object..
vec2 intersecX = getIntersect(m_pos1, m_axeX,
m_pos2, m_axeY);
vec2 intersecY = getIntersect(m_pos1, m_axeY,
m_pos2, m_axeX);
m_baseSize = vec2((m_pos1 - intersecX).length(),
(m_pos1 - intersecY).length());
// get all the colors
m_data = gradient->getColors(_document);
}
#undef __class__
#define __class__ "render:DynamicColor"
@ -217,7 +353,7 @@ std::shared_ptr<esvg::render::DynamicColor> esvg::render::createColor(std::pair<
return nullptr;
}
if (_color.second != "") {
return std::make_shared<esvg::render::DynamicColorLinear>(_color.second, _mtx);
return std::make_shared<esvg::render::DynamicColorSpecial>(_color.second, _mtx);
}
return std::make_shared<esvg::render::DynamicColorUni>(_color.first);
}

View File

@ -48,22 +48,28 @@ namespace esvg {
// nothing to do ...
};
};
class DynamicColorLinear : public esvg::render::DynamicColor {
class DynamicColorSpecial : public esvg::render::DynamicColor {
public:
bool m_linear;
esvg::spreadMethod m_spread;
esvg::gradientUnits m_unit;
std::string m_colorName;
mat2 m_matrix;
std::pair<vec2, vec2> m_viewPort;
vec2 m_pos1;
vec2 m_pos2;
vec2 m_pos1; // in radius ==> center
vec2 m_pos2; // in radius ==> radius end position
vec2 m_focal; // Specific radius
vec2 m_axeX;
vec2 m_axeY;
vec2 m_baseSize;
std::vector<std::pair<float, etk::Color<float,4>>> m_data;
public:
DynamicColorLinear(const std::string& _link, const mat2& _mtx);
DynamicColorSpecial(const std::string& _link, const mat2& _mtx);
virtual etk::Color<float,4> getColor(const ivec2& _pos);
private:
etk::Color<float,4> getColorLinear(const ivec2& _pos);
etk::Color<float,4> getColorRadial(const ivec2& _pos);
public:
virtual void generate(esvg::Document* _document);
virtual void setViewPort(const std::pair<vec2, vec2>& _viewPort);
};

View File

@ -259,7 +259,7 @@ TEST(TestGradientLinear, unitBox_spreadReflect) {
}
TEST(TestGradientLinear, unitBox_spreadRepeate) {
TEST(TestGradientLinear, unitBox_spreadRepeat) {
std::string data("<?xml version='1.0' encoding='UTF-8' standalone='no'?>\n"
"<svg height='100' width='100'>\n"
" <defs>\n"
@ -272,8 +272,8 @@ TEST(TestGradientLinear, unitBox_spreadRepeate) {
"</svg>\n");
esvg::Document doc;
doc.parse(data);
etk::FSNodeWriteAllData("TestGradientLinear_unitBox_spreadRepeate.svg", data);
doc.generateAnImage(ivec2(100, 100), "TestGradientLinear_unitBox_spreadRepeate.bmp", g_visualDebug);
etk::FSNodeWriteAllData("TestGradientLinear_unitBox_spreadRepeat.svg", data);
doc.generateAnImage(ivec2(100, 100), "TestGradientLinear_unitBox_spreadRepeat.bmp", g_visualDebug);
}
TEST(TestGradientLinear, unitUser_spreadNone) {

View File

@ -13,13 +13,35 @@
#undef __class__
#define __class__ "TestGradientRadial"
TEST(TestGradientRadial, circle) {
std::string data("<?xml version='1.0' encoding='UTF-8' standalone='no'?>\n"
"<svg height='100' width='100'>\n"
" <defs>\n"
" <radialGradient id='grad1' cx='50%' cy='50%' r='50%' fx='50%' fy='50%'>\n"
" <stop offset='0%' style='stop-color:orange;stop-opacity:1' />\n"
" <stop offset='45%' style='stop-color:red;stop-opacity:1' />\n"
" <stop offset='55%' style='stop-color:blue;stop-opacity:1' />\n"
" <stop offset='100%' style='stop-color:green;stop-opacity:1' />\n"
" </radialGradient>\n"
" </defs>\n"
" <ellipse cx='50' cy='50' rx='50' ry='50' fill='url(#grad1)' />\n"
"</svg>\n");
esvg::Document doc;
doc.parse(data);
etk::FSNodeWriteAllData("TestGradientRadial_circle.svg", data);
doc.generateAnImage(ivec2(100, 100), "TestGradientRadial_circle.bmp", g_visualDebug);
}
TEST(TestGradientRadial, full) {
std::string data("<?xml version='1.0' encoding='UTF-8' standalone='no'?>\n"
"<svg height='100' width='100'>\n"
" <defs>\n"
" <radialGradient id='grad1' cx='50%' cy='50%' r='50%' fx='50%' fy='50%'>\n"
" <stop offset='0%' style='stop-color:rgb(255,255,255);stop-opacity:0' />\n"
" <stop offset='100%' style='stop-color:rgb(0,0,255);stop-opacity:1' />\n"
" <stop offset='0%' style='stop-color:orange;stop-opacity:1' />\n"
" <stop offset='45%' style='stop-color:red;stop-opacity:1' />\n"
" <stop offset='55%' style='stop-color:blue;stop-opacity:1' />\n"
" <stop offset='100%' style='stop-color:green;stop-opacity:1' />\n"
" </radialGradient>\n"
" </defs>\n"
" <ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad1)' />\n"
@ -36,8 +58,10 @@ TEST(TestGradientRadial, partial) {
"<svg height='100' width='100'>\n"
" <defs>\n"
" <radialGradient id='grad2' cx='20%' cy='30%' r='30%' fx='50%' fy='50%'>\n"
" <stop offset='0%' style='stop-color:rgb(255,255,255);stop-opacity:0' />\n"
" <stop offset='100%' style='stop-color:rgb(0,0,255);stop-opacity:1' />\n"
" <stop offset='0%' style='stop-color:orange;stop-opacity:1' />\n"
" <stop offset='45%' style='stop-color:red;stop-opacity:1' />\n"
" <stop offset='55%' style='stop-color:blue;stop-opacity:1' />\n"
" <stop offset='100%' style='stop-color:green;stop-opacity:1' />\n"
" </radialGradient>\n"
" </defs>\n"
" <ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad2)' />\n"
@ -46,4 +70,161 @@ TEST(TestGradientRadial, partial) {
doc.parse(data);
etk::FSNodeWriteAllData("TestGradientRadial_partial.svg", data);
doc.generateAnImage(ivec2(100, 100), "TestGradientRadial_partial.bmp", g_visualDebug);
}
}
TEST(TestGradientRadial, unitBox_spreadNone) {
std::string data("<?xml version='1.0' encoding='UTF-8' standalone='no'?>\n"
"<svg height='100' width='100'>\n"
" <defs>\n"
" <radialGradient id='grad1' cx='50%' cy='50%' r='10%' fx='50%' fy='50%'>\n"
" <stop offset='0%' style='stop-color:orange;stop-opacity:1' />\n"
" <stop offset='45%' style='stop-color:red;stop-opacity:1' />\n"
" <stop offset='55%' style='stop-color:blue;stop-opacity:1' />\n"
" <stop offset='100%' style='stop-color:green;stop-opacity:1' />\n"
" </radialGradient>\n"
" </defs>\n"
" <ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad1)' />\n"
"</svg>\n");
esvg::Document doc;
doc.parse(data);
etk::FSNodeWriteAllData("TestGradientRadial_unitBox_spreadNone.svg", data);
doc.generateAnImage(ivec2(100, 100), "TestGradientRadial_unitBox_spreadNone.bmp", g_visualDebug);
}
TEST(TestGradientRadial, unitBox_spreadPad) {
std::string data("<?xml version='1.0' encoding='UTF-8' standalone='no'?>\n"
"<svg height='100' width='100'>\n"
" <defs>\n"
" <radialGradient id='grad1' cx='50%' cy='50%' r='10%' fx='50%' fy='50%' spreadMethod='pad'>\n"
" <stop offset='0%' style='stop-color:orange;stop-opacity:1' />\n"
" <stop offset='45%' style='stop-color:red;stop-opacity:1' />\n"
" <stop offset='55%' style='stop-color:blue;stop-opacity:1' />\n"
" <stop offset='100%' style='stop-color:green;stop-opacity:1' />\n"
" </radialGradient>\n"
" </defs>\n"
" <ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad1)' />\n"
"</svg>\n");
esvg::Document doc;
doc.parse(data);
etk::FSNodeWriteAllData("TestGradientRadial_unitBox_spreadPad.svg", data);
doc.generateAnImage(ivec2(100, 100), "TestGradientRadial_unitBox_spreadPad.bmp", g_visualDebug);
}
TEST(TestGradientRadial, unitBox_spreadReflect) {
std::string data("<?xml version='1.0' encoding='UTF-8' standalone='no'?>\n"
"<svg height='100' width='100'>\n"
" <defs>\n"
" <radialGradient id='grad1' cx='50%' cy='50%' r='10%' fx='50%' fy='50%' spreadMethod='reflect'>\n"
" <stop offset='0%' style='stop-color:orange;stop-opacity:1' />\n"
" <stop offset='45%' style='stop-color:red;stop-opacity:1' />\n"
" <stop offset='55%' style='stop-color:blue;stop-opacity:1' />\n"
" <stop offset='100%' style='stop-color:green;stop-opacity:1' />\n"
" </radialGradient>\n"
" </defs>\n"
" <ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad1)' />\n"
"</svg>\n");
esvg::Document doc;
doc.parse(data);
etk::FSNodeWriteAllData("TestGradientRadial_unitBox_spreadReflect.svg", data);
doc.generateAnImage(ivec2(100, 100), "TestGradientRadial_unitBox_spreadReflect.bmp", g_visualDebug);
}
TEST(TestGradientRadial, unitBox_spreadRepeat) {
std::string data("<?xml version='1.0' encoding='UTF-8' standalone='no'?>\n"
"<svg height='100' width='100'>\n"
" <defs>\n"
" <radialGradient id='grad1' cx='50%' cy='50%' r='10%' fx='50%' fy='50%' spreadMethod='repeat'>\n"
" <stop offset='0%' style='stop-color:orange;stop-opacity:1' />\n"
" <stop offset='45%' style='stop-color:red;stop-opacity:1' />\n"
" <stop offset='55%' style='stop-color:blue;stop-opacity:1' />\n"
" <stop offset='100%' style='stop-color:green;stop-opacity:1' />\n"
" </radialGradient>\n"
" </defs>\n"
" <ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad1)' />\n"
"</svg>\n");
esvg::Document doc;
doc.parse(data);
etk::FSNodeWriteAllData("TestGradientRadial_unitBox_spreadRepeat.svg", data);
doc.generateAnImage(ivec2(100, 100), "TestGradientRadial_unitBox_spreadRepeat.bmp", g_visualDebug);
}
TEST(TestGradientRadial, unitUser_spreadNone) {
std::string data("<?xml version='1.0' encoding='UTF-8' standalone='no'?>\n"
"<svg height='100' width='100'>\n"
" <defs>\n"
" <radialGradient id='grad1' cx='50' cy='50' r='10' fx='50' fy='50%' gradientUnits='userSpaceOnUse' >\n"
" <stop offset='0%' style='stop-color:orange;stop-opacity:1' />\n"
" <stop offset='45%' style='stop-color:red;stop-opacity:1' />\n"
" <stop offset='55%' style='stop-color:blue;stop-opacity:1' />\n"
" <stop offset='100%' style='stop-color:green;stop-opacity:1' />\n"
" </radialGradient>\n"
" </defs>\n"
" <ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad1)' />\n"
"</svg>\n");
esvg::Document doc;
doc.parse(data);
etk::FSNodeWriteAllData("TestGradientRadial_unitUser_spreadNone.svg", data);
doc.generateAnImage(ivec2(100, 100), "TestGradientRadial_unitUser_spreadNone.bmp", g_visualDebug);
}
TEST(TestGradientRadial, unitUser_spreadPad) {
std::string data("<?xml version='1.0' encoding='UTF-8' standalone='no'?>\n"
"<svg height='100' width='100'>\n"
" <defs>\n"
" <radialGradient id='grad1' cx='50' cy='50' r='10' fx='50' fy='50' spreadMethod='pad' gradientUnits='userSpaceOnUse' >\n"
" <stop offset='0%' style='stop-color:orange;stop-opacity:1' />\n"
" <stop offset='45%' style='stop-color:red;stop-opacity:1' />\n"
" <stop offset='55%' style='stop-color:blue;stop-opacity:1' />\n"
" <stop offset='100%' style='stop-color:green;stop-opacity:1' />\n"
" </radialGradient>\n"
" </defs>\n"
" <ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad1)' />\n"
"</svg>\n");
esvg::Document doc;
doc.parse(data);
etk::FSNodeWriteAllData("TestGradientRadial_unitUser_spreadPad.svg", data);
doc.generateAnImage(ivec2(100, 100), "TestGradientRadial_unitUser_spreadPad.bmp", g_visualDebug);
}
TEST(TestGradientRadial, unitUser_spreadReflect) {
std::string data("<?xml version='1.0' encoding='UTF-8' standalone='no'?>\n"
"<svg height='100' width='100'>\n"
" <defs>\n"
" <radialGradient id='grad1' cx='50' cy='50' r='10' fx='50' fy='50' spreadMethod='reflect' gradientUnits='userSpaceOnUse' >\n"
" <stop offset='0%' style='stop-color:orange;stop-opacity:1' />\n"
" <stop offset='45%' style='stop-color:red;stop-opacity:1' />\n"
" <stop offset='55%' style='stop-color:blue;stop-opacity:1' />\n"
" <stop offset='100%' style='stop-color:green;stop-opacity:1' />\n"
" </radialGradient>\n"
" </defs>\n"
" <ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad1)' />\n"
"</svg>\n");
esvg::Document doc;
doc.parse(data);
etk::FSNodeWriteAllData("TestGradientRadial_unitUser_spreadReflect.svg", data);
doc.generateAnImage(ivec2(100, 100), "TestGradientRadial_unitUser_spreadReflect.bmp", g_visualDebug);
}
TEST(TestGradientRadial, unitUser_spreadRepeat) {
std::string data("<?xml version='1.0' encoding='UTF-8' standalone='no'?>\n"
"<svg height='100' width='100'>\n"
" <defs>\n"
" <radialGradient id='grad1' cx='50' cy='50' r='10' fx='50' fy='50' spreadMethod='repeat' gradientUnits='userSpaceOnUse' >\n"
" <stop offset='0%' style='stop-color:orange;stop-opacity:1' />\n"
" <stop offset='45%' style='stop-color:red;stop-opacity:1' />\n"
" <stop offset='55%' style='stop-color:blue;stop-opacity:1' />\n"
" <stop offset='100%' style='stop-color:green;stop-opacity:1' />\n"
" </radialGradient>\n"
" </defs>\n"
" <ellipse cx='50' cy='50' rx='50' ry='20' fill='url(#grad1)' />\n"
"</svg>\n");
esvg::Document doc;
doc.parse(data);
etk::FSNodeWriteAllData("TestGradientRadial_unitUser_spreadRepeat.svg", data);
doc.generateAnImage(ivec2(100, 100), "TestGradientRadial_unitUser_spreadRepeat.bmp", g_visualDebug);
}