diff --git a/.gitignore b/.gitignore
index f9d34141..6f1942f4 100644
--- a/.gitignore
+++ b/.gitignore
@@ -72,3 +72,5 @@ debug-mod/
local-mod/
local-gdb/
out/
+3rdparty/blend2d/
+3rdparty/blend2d-apps/
diff --git a/examples/vue.fluid b/examples/vue.fluid
index 3c003bb5..e4dbfb5e 100644
--- a/examples/vue.fluid
+++ b/examples/vue.fluid
@@ -1,14 +1,5 @@
--[[
A file viewer for recognised documents like SVG and RIPL
-
-Example: parasol vue.fluid file=[Path]
-
-Optional parameters are:
-
- width: Width of the application window
- height: Height of the application window
- path: Path to use in the file selector.
- file: A source file to load and display in the application.
--]]
require 'gui'
@@ -44,6 +35,7 @@ Optional parameters are:
height | Height of the application window. |
path | Path to use in the file selector. |
file | A source file to load and display in the application. |
+no-browser | Hide the file browser. |
@@ -191,50 +183,58 @@ end
glViewport = glWindow:clientViewport({ aspectRatio = ARF_MEET })
- -- File view on the left
-
- glView = gui.listView({
- target = glViewport,
- x = glWindow.margins.left,
- y = glWindow.margins.top,
- width = 200,
- yOffset = glWindow.margins.top,
- dragDrop = true,
- sensitive = true,
- multiSelect = false,
- borderless = true
- })
+ if arg('no-browser') then
+ glViewArea = glViewport.new('VectorViewport', {
+ x=glWindow.margins.left, y=glWindow.margins.top,
+ xOffset=glWindow.margins.right, yOffset=glWindow.margins.top
+ })
+ else
+ -- File view on the left
+
+ glView = gui.listView({
+ target = glViewport,
+ x = glWindow.margins.left,
+ y = glWindow.margins.top,
+ width = 200,
+ yOffset = glWindow.margins.top,
+ dragDrop = true,
+ sensitive = true,
+ multiSelect = false,
+ borderless = true
+ })
- glFileview = gui.fileview(glView, {
- navigationBar = true,
- path = arg('path', ':'),
- filterList = {
- { name='SVG Images', pattern='.svg' },
- { name='RIPL Documents', pattern={ '.ripl', '.rpl' } },
- { name='JPEG Images', pattern={ '.jpeg', '.jpg' } },
- { name='PNG Images', pattern='.png' }
- },
- fileSelected = function(FileView)
- displayFile(FileView.selectionPath())
- title = FileView.selectionFile()
- if glStats.width and glStats.height then
- title = title .. ' [ ' .. glStats.width .. ' x ' .. glStats.height .. ' ]'
+ glFileview = gui.fileview(glView, {
+ navigationBar = true,
+ displayPath = true,
+ path = arg('path', ':'),
+ filterList = {
+ { name='SVG Images', pattern='.svg' },
+ { name='RIPL Documents', pattern={ '.ripl', '.rpl' } },
+ { name='JPEG Images', pattern={ '.jpeg', '.jpg' } },
+ { name='PNG Images', pattern='.png' }
+ },
+ fileSelected = function(FileView)
+ displayFile(FileView.selectionPath())
+ title = FileView.selectionFile()
+ if glStats.width and glStats.height then
+ title = title .. ' [ ' .. glStats.width .. ' x ' .. glStats.height .. ' ]'
+ end
+ glWindow:setTitle(title)
end
- glWindow:setTitle(title)
- end
- })
+ })
- -- Document viewer on the right
+ -- Document viewer on the right
- glViewArea = glViewport.new('VectorViewport', {
- x=glView.viewport.x + glView.viewport.width + 6, y=glWindow.margins.top,
- xOffset=glWindow.margins.right, yOffset=glWindow.margins.top
- })
+ glViewArea = glViewport.new('VectorViewport', {
+ x=glView.viewport.x + glView.viewport.width + 6, y=glWindow.margins.top,
+ xOffset=glWindow.margins.right, yOffset=glWindow.margins.top
+ })
- gui.divider({
- left = glView.viewport, right = glViewArea,
- minA = 100, maxA = glWindow.surface.insideWidth * 0.4, minB = 100
- })
+ gui.divider({
+ left = glView.viewport, right = glViewArea,
+ minA = 100, maxA = glWindow.surface.insideWidth * 0.4, minB = 100
+ })
+ end
-- Display a file from the commandline, or show the application documentation.
diff --git a/scripts/gui.fluid b/scripts/gui.fluid
index 00f12899..ca1f652c 100644
--- a/scripts/gui.fluid
+++ b/scripts/gui.fluid
@@ -371,25 +371,6 @@ gui.createIcon = function(Scene, Path, Size, Theme, Name)
end
end)
- -- Adjust gradient size to match the viewport height.
-
- local viewport = icon.pattern.viewport.child
- if viewport != nil then
- while child != nil do
- if child.class.id == ID_VECTORVIEWPORT then
- viewport = child
- break
- end
- end
-
- if viewport.viewHeight < viewport.viewWidth then
- icon.gradient.y1 = viewport.viewY - ((viewport.viewWidth - viewport.viewHeight) * 0.5)
- icon.gradient.y2 = icon.gradient.y1 + viewport.viewWidth
- else
- icon.gradient.y1 = viewport.viewY
- icon.gradient.y2 = viewport.viewY + viewport.viewHeight
- end
- end
check(Scene.mtAddDef(Name, icon.pattern))
diff --git a/src/svg/class_svg.cpp b/src/svg/class_svg.cpp
index 6ea4a40c..80a84ece 100644
--- a/src/svg/class_svg.cpp
+++ b/src/svg/class_svg.cpp
@@ -88,6 +88,7 @@ static ERR SVG_Free(extSVG *Self)
{
if (Self->AnimationTimer) {
UpdateTimer(Self->AnimationTimer, 0);
+ if (Self->Scene) UnsubscribeAction(Self->Scene, AC::Free);
Self->AnimationTimer = 0;
}
diff --git a/src/svg/tests/gradients/w3-pservers-grad-04-b.svg b/src/svg/tests/gradients/w3-pservers-grad-04-b.svg
new file mode 100644
index 00000000..66b3fc2c
--- /dev/null
+++ b/src/svg/tests/gradients/w3-pservers-grad-04-b.svg
@@ -0,0 +1,32 @@
+
diff --git a/src/svg/tests/gradients/w3-pservers-grad-05-b.svg b/src/svg/tests/gradients/w3-pservers-grad-05-b.svg
new file mode 100644
index 00000000..5f5b92b3
--- /dev/null
+++ b/src/svg/tests/gradients/w3-pservers-grad-05-b.svg
@@ -0,0 +1,29 @@
+
+
diff --git a/src/svg/tests/gradients/w3-pservers-grad-10-b.svg b/src/svg/tests/gradients/w3-pservers-grad-10-b.svg
new file mode 100644
index 00000000..82ea60b1
--- /dev/null
+++ b/src/svg/tests/gradients/w3-pservers-grad-10-b.svg
@@ -0,0 +1,35 @@
+
diff --git a/src/svg/tests/gradients/w3-pservers-grad-14-b.svg b/src/svg/tests/gradients/w3-pservers-grad-14-b.svg
new file mode 100644
index 00000000..a7528671
--- /dev/null
+++ b/src/svg/tests/gradients/w3-pservers-grad-14-b.svg
@@ -0,0 +1,76 @@
+
diff --git a/src/svg/tests/test-svg.fluid b/src/svg/tests/test-svg.fluid
index 4009de8c..58737a34 100644
--- a/src/svg/tests/test-svg.fluid
+++ b/src/svg/tests/test-svg.fluid
@@ -68,11 +68,15 @@ function testVStripes() hashTestSVG('patterns/vstripes.svg', 0x2f85dc2
function testW3Gradients01() hashTestSVG('gradients/w3-pservers-grad-01-b.svg', 0xe637a6fa) end
function testW3Gradients02() hashTestSVG('gradients/w3-pservers-grad-02-b.svg', 0x69157174) end
+function testW3Gradients04() hashTestSVG('gradients/w3-pservers-grad-04-b.svg', 0x30e19fc3) end
+function testW3Gradients05() hashTestSVG('gradients/w3-pservers-grad-05-b.svg', 0x80b6a37d) end
function testW3Gradients07() hashTestSVG('gradients/w3-pservers-grad-07-b.svg', 0xfb7be5fe) end
function testW3Gradients08() hashTestSVG('gradients/w3-pservers-grad-08-b.svg', 0x97f7b810) end
function testW3Gradients09() hashTestSVG('gradients/w3-pservers-grad-09-b.svg', 0xfd34d4f1) end
+function testW3Gradients10() hashTestSVG('gradients/w3-pservers-grad-10-b.svg', 0x8a32cb66) end
function testW3Gradients11() hashTestSVG('gradients/w3-pservers-grad-11-b.svg', 0x4f4a58f3) end
function testW3Gradients12() hashTestSVG('gradients/w3-pservers-grad-12-b.svg', 0xd59b60ce) end
+function testW3Gradients14() hashTestSVG('gradients/w3-pservers-grad-14-b.svg', 0xb26061f7) end
function testW3Gradients15() hashTestSVG('gradients/w3-pservers-grad-15-b.svg', 0x531aca96) end
function testW3Gradients22() hashTestSVG('gradients/w3-pservers-grad-22-b.svg', 0x5477019b) end
@@ -252,11 +256,15 @@ function testW3TextB25() hashTestSVG('text/w3-text-ws-03-t.svg', -1) end
'testInheritClip',
'testW3Gradients01',
'testW3Gradients02',
+ 'testW3Gradients04',
+ 'testW3Gradients05',
'testW3Gradients07',
'testW3Gradients08',
'testW3Gradients09',
+ 'testW3Gradients10',
'testW3Gradients11',
'testW3Gradients12',
+ 'testW3Gradients14',
'testW3Gradients15',
'testW3Gradients22',
-- Patterns
diff --git a/src/vector/defs/gradient.cpp b/src/vector/defs/gradient.cpp
index 07c240eb..90a2e947 100644
--- a/src/vector/defs/gradient.cpp
+++ b/src/vector/defs/gradient.cpp
@@ -618,6 +618,7 @@ static ERR VECTORGRADIENT_SET_X1(extVectorGradient *Self, Unit &Value)
if (Value.scaled()) Self->Flags = (Self->Flags | VGF::SCALED_X1) & (~VGF::FIXED_X1);
else Self->Flags = (Self->Flags | VGF::FIXED_X1) & (~VGF::SCALED_X1);
Self->X1 = Value;
+ Self->CalcAngle = true;
return ERR::Okay;
}
@@ -643,6 +644,7 @@ static ERR VECTORGRADIENT_SET_X2(extVectorGradient *Self, Unit &Value)
if (Value.scaled()) Self->Flags = (Self->Flags | VGF::SCALED_X2) & (~VGF::FIXED_X2);
else Self->Flags = (Self->Flags | VGF::FIXED_X2) & (~VGF::SCALED_X2);
Self->X2 = Value;
+ Self->CalcAngle = true;
return ERR::Okay;
}
@@ -668,6 +670,7 @@ static ERR VECTORGRADIENT_SET_Y1(extVectorGradient *Self, Unit &Value)
if (Value.scaled()) Self->Flags = (Self->Flags | VGF::SCALED_Y1) & (~VGF::FIXED_Y1);
else Self->Flags = (Self->Flags | VGF::FIXED_Y1) & (~VGF::SCALED_Y1);
Self->Y1 = Value;
+ Self->CalcAngle = true;
return ERR::Okay;
}
@@ -693,6 +696,7 @@ static ERR VECTORGRADIENT_SET_Y2(extVectorGradient *Self, Unit &Value)
if (Value.scaled()) Self->Flags = (Self->Flags | VGF::SCALED_Y2) & (~VGF::FIXED_Y2);
else Self->Flags = (Self->Flags | VGF::FIXED_Y2) & (~VGF::SCALED_Y2);
Self->Y2 = Value;
+ Self->CalcAngle = true;
return ERR::Okay;
}
diff --git a/src/vector/scene/scene.cpp b/src/vector/scene/scene.cpp
index 58ad2345..7b259fe2 100644
--- a/src/vector/scene/scene.cpp
+++ b/src/vector/scene/scene.cpp
@@ -46,7 +46,7 @@ static void fill_image(VectorState &, const TClipRectangle &, agg::path_
agg::rasterizer_scanline_aa<> &, DOUBLE Alpha = 1.0);
static void fill_gradient(VectorState &, const TClipRectangle &, agg::path_storage *,
- const agg::trans_affine &, DOUBLE, DOUBLE, const extVectorGradient &, GRADIENT_TABLE *,
+ const agg::trans_affine &, DOUBLE, DOUBLE, extVectorGradient &, GRADIENT_TABLE *,
agg::renderer_base &, agg::rasterizer_scanline_aa<> &);
static void fill_pattern(VectorState &, const TClipRectangle &, agg::path_storage *,
diff --git a/src/vector/scene/scene_fill.cpp b/src/vector/scene/scene_fill.cpp
index 684ba518..f3ce31af 100644
--- a/src/vector/scene/scene_fill.cpp
+++ b/src/vector/scene/scene_fill.cpp
@@ -61,19 +61,19 @@ void SceneRenderer::render_fill(VectorState &State, extVector &Vector, agg::rast
// Path: The original vector path without transforms.
// Transform: Transforms to be applied to the path and to align the image.
-static void fill_image(VectorState &State, const TClipRectangle &Bounds, agg::path_storage &Path, VSM SampleMethod,
- const agg::trans_affine &Transform, DOUBLE ViewWidth, DOUBLE ViewHeight,
+static void fill_image(VectorState &State, const TClipRectangle &Bounds, agg::path_storage &Path, VSM SampleMethod,
+ const agg::trans_affine &Transform, double ViewWidth, double ViewHeight,
objVectorImage &Image, agg::renderer_base &RenderBase,
- agg::rasterizer_scanline_aa<> &Raster, DOUBLE Alpha)
+ agg::rasterizer_scanline_aa<> &Raster, double Alpha)
{
- const DOUBLE c_width = (Image.Units IS VUNIT::USERSPACE) ? ViewWidth : Bounds.width();
- const DOUBLE c_height = (Image.Units IS VUNIT::USERSPACE) ? ViewHeight : Bounds.height();
- const DOUBLE dx = Bounds.left + (dmf::hasScaledX(Image.Dimensions) ? (c_width * Image.X) : Image.X);
- const DOUBLE dy = Bounds.top + (dmf::hasScaledY(Image.Dimensions) ? (c_height * Image.Y) : Image.Y);
+ const double c_width = (Image.Units IS VUNIT::USERSPACE) ? ViewWidth : Bounds.width();
+ const double c_height = (Image.Units IS VUNIT::USERSPACE) ? ViewHeight : Bounds.height();
+ const double dx = Bounds.left + (dmf::hasScaledX(Image.Dimensions) ? (c_width * Image.X) : Image.X);
+ const double dy = Bounds.top + (dmf::hasScaledY(Image.Dimensions) ? (c_height * Image.Y) : Image.Y);
Path.approximation_scale(Transform.scale());
- DOUBLE x_scale, y_scale, x_offset, y_offset;
+ double x_scale, y_scale, x_offset, y_offset;
calc_aspectratio("fill_image", Image.AspectRatio, c_width, c_height,
Image.Bitmap->Width, Image.Bitmap->Height, &x_offset, &y_offset, &x_scale, &y_scale);
@@ -100,28 +100,29 @@ static void fill_image(VectorState &State, const TClipRectangle &Bounds,
// The Raster must contain the shape's path.
// TODO: Support gradient_xy (rounded corner), gradient_sqrt_xy
-static void fill_gradient(VectorState &State, const TClipRectangle &Bounds, agg::path_storage *Path,
- const agg::trans_affine &Transform, DOUBLE ViewWidth, DOUBLE ViewHeight, const extVectorGradient &Gradient,
+static void fill_gradient(VectorState &State, const TClipRectangle &Bounds, agg::path_storage *Path,
+ const agg::trans_affine &Transform, double ViewWidth, double ViewHeight, extVectorGradient &Gradient,
GRADIENT_TABLE *Table, agg::renderer_base &RenderBase,
agg::rasterizer_scanline_aa<> &Raster)
{
+ constexpr LONG MAX_SPAN = 256;
typedef agg::span_interpolator_linear<> interpolator_type;
typedef agg::span_allocator span_allocator_type;
- typedef agg::pod_auto_array color_array_type;
+ typedef agg::pod_auto_array color_array_type;
typedef agg::renderer_base RENDERER_BASE_TYPE;
agg::trans_affine transform;
interpolator_type span_interpolator(transform);
span_allocator_type span_allocator;
- const DOUBLE c_width = Gradient.Units IS VUNIT::USERSPACE ? ViewWidth : Bounds.width();
- const DOUBLE c_height = Gradient.Units IS VUNIT::USERSPACE ? ViewHeight : Bounds.height();
- const DOUBLE x_offset = Gradient.Units IS VUNIT::USERSPACE ? 0 : Bounds.left;
- const DOUBLE y_offset = Gradient.Units IS VUNIT::USERSPACE ? 0 : Bounds.top;
+ const double c_width = Gradient.Units IS VUNIT::USERSPACE ? ViewWidth : Bounds.width();
+ const double c_height = Gradient.Units IS VUNIT::USERSPACE ? ViewHeight : Bounds.height();
+ const double x_offset = Gradient.Units IS VUNIT::USERSPACE ? 0 : Bounds.left;
+ const double y_offset = Gradient.Units IS VUNIT::USERSPACE ? 0 : Bounds.top;
Path->approximation_scale(Transform.scale());
- auto render_gradient = [&](S SpreadMethod, DOUBLE Span) {
+ auto render_gradient = [&](S SpreadMethod, double Span) {
typedef agg::span_gradient span_gradient_type;
typedef agg::renderer_scanline_aa renderer_gradient_type;
@@ -140,47 +141,70 @@ static void fill_gradient(VectorState &State, const TClipRectangle &Boun
};
if (Gradient.Type IS VGT::LINEAR) {
- TClipRectangle area;
-
- if ((Gradient.Flags & VGF::SCALED_X1) != VGF::NIL) area.left = x_offset + (c_width * Gradient.X1);
- else area.left = x_offset + Gradient.X1;
-
- if ((Gradient.Flags & VGF::SCALED_X2) != VGF::NIL) area.right = x_offset + (c_width * Gradient.X2);
- else area.right = x_offset + Gradient.X2;
-
- if ((Gradient.Flags & VGF::SCALED_Y1) != VGF::NIL) area.top = y_offset + (c_height * Gradient.Y1);
- else area.top = y_offset + Gradient.Y1;
+ auto span = MAX_SPAN;
+ if (Gradient.Units IS VUNIT::BOUNDING_BOX) {
+ // NOTE: In this mode we are mapping a 1x1 gradient square into the target path, which means
+ // the gradient is stretched into position as a square. We don't map the (X,Y) points to the
+ // bounding box and draw point-to-point.
+
+ const double x = x_offset + (c_width * Gradient.X1);
+ const double y = y_offset + (c_height * Gradient.Y1);
+
+ if (Gradient.CalcAngle) {
+ const double dx = Gradient.X2 - Gradient.X1;
+ const double dy = Gradient.Y2 - Gradient.Y1;
+ Gradient.Angle = atan2(dy, dx);
+ Gradient.Length = sqrt((dx * dx) + (dy * dy));
+ Gradient.CalcAngle = false;
+ }
- if ((Gradient.Flags & VGF::SCALED_Y2) != VGF::NIL) area.bottom = y_offset + (c_height * Gradient.Y2);
- else area.bottom = y_offset + Gradient.Y2;
+ transform.scale(Gradient.Length);
+ transform.rotate(Gradient.Angle);
+ transform.scale(c_width / span, c_height / span);
+ transform.translate(x, y);
+ }
+ else {
+ TClipRectangle area;
+ if ((Gradient.Flags & VGF::SCALED_X1) != VGF::NIL) area.left = x_offset + (c_width * Gradient.X1);
+ else area.left = x_offset + Gradient.X1;
+
+ if ((Gradient.Flags & VGF::SCALED_X2) != VGF::NIL) area.right = x_offset + (c_width * Gradient.X2);
+ else area.right = x_offset + Gradient.X2;
+
+ if ((Gradient.Flags & VGF::SCALED_Y1) != VGF::NIL) area.top = y_offset + (c_height * Gradient.Y1);
+ else area.top = y_offset + Gradient.Y1;
+
+ if ((Gradient.Flags & VGF::SCALED_Y2) != VGF::NIL) area.bottom = y_offset + (c_height * Gradient.Y2);
+ else area.bottom = y_offset + Gradient.Y2;
+
+ if (Gradient.CalcAngle) {
+ const double dx = area.width();
+ const double dy = area.height();
+ Gradient.Angle = atan2(dy, dx);
+ Gradient.Length = sqrt((dx * dx) + (dy * dy));
+ Gradient.CalcAngle = false;
+ }
- // Calculate the gradient's transition from the point at (x1,y1) to (x2,y2)
+ transform.scale(Gradient.Length / span);
+ transform.rotate(Gradient.Angle);
+ transform.translate(area.left, area.top);
+ }
- const DOUBLE dx = area.width();
- const DOUBLE dy = area.height();
- transform.scale(sqrt((dx * dx) + (dy * dy)) / 256.0);
- transform.rotate(atan2(dy, dx));
- transform.translate(area.left, area.top);
apply_transforms(Gradient, transform);
transform *= Transform;
transform.invert();
- agg::gradient_x gradient_func; // gradient_x is a horizontal gradient with infinite height
- typedef agg::span_gradient span_gradient_type;
- typedef agg::renderer_scanline_aa renderer_gradient_type;
- span_gradient_type span_gradient(span_interpolator, gradient_func, *Table, 0, 256);
- renderer_gradient_type solidgrad(RenderBase, span_allocator, span_gradient);
+ agg::gradient_x gradient_func;
- if (State.mClipStack->empty()) {
- agg::scanline_u8 scanline;
- agg::render_scanlines(Raster, scanline, solidgrad);
+ if (Gradient.SpreadMethod IS VSPREAD::REFLECT) {
+ agg::gradient_reflect_adaptor spread_method(gradient_func);
+ render_gradient(spread_method, span);
}
- else { // Masked gradient
- agg::alpha_mask_gray8 alpha_mask(State.mClipStack->top().m_renderer);
- agg::scanline_u8_am masked_scanline(alpha_mask);
-
- agg::render_scanlines(Raster, masked_scanline, solidgrad);
+ else if (Gradient.SpreadMethod IS VSPREAD::REPEAT) {
+ agg::gradient_repeat_adaptor spread_method(gradient_func);
+ render_gradient(spread_method, span);
}
+ else render_gradient(gradient_func, span);
}
else if (Gradient.Type IS VGT::RADIAL) {
agg::point_d c, f;
@@ -202,26 +226,21 @@ static void fill_gradient(VectorState &State, const TClipRectangle &Boun
if ((c.x IS f.x) and (c.y IS f.y)) {
// Standard radial gradient, where the focal point is the same as the gradient center
- DOUBLE radial_col_span = Gradient.Radius;
+ double radial_col_span = Gradient.Radius;
if (Gradient.Units IS VUNIT::USERSPACE) { // Coordinates are relative to the viewport
if ((Gradient.Flags & VGF::SCALED_RADIUS) != VGF::NIL) { // Gradient is a ratio of the viewport's dimensions
radial_col_span = (ViewWidth + ViewHeight) * Gradient.Radius * 0.5;
}
}
else { // Coordinates are scaled to the bounding box
- if ((Gradient.Flags & VGF::SCALED_RADIUS) != VGF::NIL) {
- // Set radial_col_span to the wider of the width/height
- if (c_height > c_width) {
- radial_col_span = c_height * Gradient.Radius;
- transform.scaleX(c_width / c_height);
- }
- else {
- radial_col_span = c_width * Gradient.Radius;
- transform.scaleY(c_height / c_width);
- }
+ // Set radial_col_span to the wider of the width/height
+ if (c_height > c_width) {
+ radial_col_span = c_height * Gradient.Radius;
+ transform.scaleX(c_width / c_height);
}
else {
- //transform *= agg::trans_affine_scaling(Gradient.Radius * 0.01 / radial_col_span);
+ radial_col_span = c_width * Gradient.Radius;
+ transform.scaleY(c_height / c_width);
}
}
@@ -230,6 +249,10 @@ static void fill_gradient(VectorState &State, const TClipRectangle &Boun
transform.scale(radial_col_span * (1.0 / MIN_SPAN));
radial_col_span = MIN_SPAN;
}
+ else if (radial_col_span > MAX_SPAN) {
+ transform.scale(radial_col_span * (1.0 / MAX_SPAN));
+ radial_col_span = MAX_SPAN;
+ }
transform.translate(c);
apply_transforms(Gradient, transform);
@@ -253,8 +276,8 @@ static void fill_gradient(VectorState &State, const TClipRectangle &Boun
// the SVG standard, the focal point had to be within the base radius. Later specifications allowed it to
// be placed outside of that radius.
- DOUBLE radial_col_span = Gradient.Radius;
- DOUBLE focal_radius = Gradient.FocalRadius;
+ double radial_col_span = Gradient.Radius;
+ double focal_radius = Gradient.FocalRadius;
if (focal_radius <= 0) focal_radius = Gradient.Radius;
if (Gradient.Units IS VUNIT::USERSPACE) { // Coordinates are relative to the viewport
@@ -264,21 +287,16 @@ static void fill_gradient(VectorState &State, const TClipRectangle &Boun
}
}
else { // Coordinates are scaled to the bounding box
- if ((Gradient.Flags & VGF::SCALED_RADIUS) != VGF::NIL) {
- // Set radial_col_span to the wider of the width/height
- if (c_height > c_width) {
- radial_col_span = c_height * radial_col_span;
- focal_radius = c_height * focal_radius;
- transform.scaleX(c_width / c_height);
- }
- else {
- radial_col_span = c_width * radial_col_span;
- focal_radius = c_width * focal_radius;
- transform.scaleY(c_height / c_width);
- }
+ // Set radial_col_span to the wider of the width/height
+ if (c_height > c_width) {
+ radial_col_span = c_height * radial_col_span;
+ focal_radius = c_height * focal_radius;
+ transform.scaleX(c_width / c_height);
}
else {
- //transform *= agg::trans_affine_scaling(Gradient.Radius * 0.01 / radial_col_span);
+ radial_col_span = c_width * radial_col_span;
+ focal_radius = c_width * focal_radius;
+ transform.scaleY(c_height / c_width);
}
}
@@ -315,7 +333,7 @@ static void fill_gradient(VectorState &State, const TClipRectangle &Boun
// Standard diamond gradient, where the focal point is the same as the gradient center
- DOUBLE radial_col_span = Gradient.Radius;
+ double radial_col_span = Gradient.Radius;
if (Gradient.Units IS VUNIT::USERSPACE) {
if ((Gradient.Flags & VGF::SCALED_RADIUS) != VGF::NIL) {
radial_col_span = (ViewWidth + ViewHeight) * Gradient.Radius * 0.5;
@@ -323,18 +341,15 @@ static void fill_gradient(VectorState &State, const TClipRectangle &Boun
else transform *= agg::trans_affine_scaling(Gradient.Radius * 0.01);
}
else { // Align to vector's bounding box
- if ((Gradient.Flags & VGF::SCALED_RADIUS) != VGF::NIL) {
- // Set radial_col_span to the wider of the width/height
- if (c_height > c_width) {
- radial_col_span = c_height * Gradient.Radius;
- transform.scaleX(c_width / c_height);
- }
- else {
- radial_col_span = c_width * Gradient.Radius;
- transform.scaleY(c_height / c_width);
- }
+ // Set radial_col_span to the wider of the width/height
+ if (c_height > c_width) {
+ radial_col_span = c_height * Gradient.Radius;
+ transform.scaleX(c_width / c_height);
+ }
+ else {
+ radial_col_span = c_width * Gradient.Radius;
+ transform.scaleY(c_height / c_width);
}
- else transform *= agg::trans_affine_scaling(Gradient.Radius * 0.01);
}
agg::gradient_diamond gradient_func;
@@ -365,7 +380,7 @@ static void fill_gradient(VectorState &State, const TClipRectangle &Boun
// Standard conic gradient, where the focal point is the same as the gradient center
- DOUBLE radial_col_span = Gradient.Radius;
+ double radial_col_span = Gradient.Radius;
if (Gradient.Units IS VUNIT::USERSPACE) {
if ((Gradient.Flags & VGF::SCALED_RADIUS) != VGF::NIL) {
radial_col_span = (ViewWidth + ViewHeight) * Gradient.Radius * 0.5;
@@ -373,18 +388,15 @@ static void fill_gradient(VectorState &State, const TClipRectangle &Boun
else transform *= agg::trans_affine_scaling(Gradient.Radius * 0.01);
}
else { // Bounding box
- if ((Gradient.Flags & VGF::SCALED_RADIUS) != VGF::NIL) {
- // Set radial_col_span to the wider of the width/height
- if (c_height > c_width) {
- radial_col_span = c_height * Gradient.Radius;
- transform.scaleX(c_width / c_height);
- }
- else {
- radial_col_span = c_width * Gradient.Radius;
- transform.scaleY(c_height / c_width);
- }
+ // Set radial_col_span to the wider of the width/height
+ if (c_height > c_width) {
+ radial_col_span = c_height * Gradient.Radius;
+ transform.scaleX(c_width / c_height);
+ }
+ else {
+ radial_col_span = c_width * Gradient.Radius;
+ transform.scaleY(c_height / c_width);
}
- else transform *= agg::trans_affine_scaling(Gradient.Radius * 0.01);
}
agg::gradient_conic gradient_func;
@@ -438,20 +450,20 @@ static void fill_gradient(VectorState &State, const TClipRectangle &Boun
// Patterns rendered with BOUNDING_BOX require real-time calculation as they have a dependency on the target
// vector's dimensions.
-static void fill_pattern(VectorState &State, const TClipRectangle &Bounds, agg::path_storage *Path,
- VSM SampleMethod, const agg::trans_affine &Transform, DOUBLE ViewWidth, DOUBLE ViewHeight,
+static void fill_pattern(VectorState &State, const TClipRectangle &Bounds, agg::path_storage *Path,
+ VSM SampleMethod, const agg::trans_affine &Transform, double ViewWidth, double ViewHeight,
extVectorPattern &Pattern, agg::renderer_base &RenderBase,
agg::rasterizer_scanline_aa<> &Raster)
{
- const DOUBLE c_width = (Pattern.Units IS VUNIT::USERSPACE) ? ViewWidth : Bounds.width();
- const DOUBLE c_height = (Pattern.Units IS VUNIT::USERSPACE) ? ViewHeight : Bounds.height();
- const DOUBLE x_offset = (Pattern.Units IS VUNIT::USERSPACE) ? 0 : Bounds.left;
- const DOUBLE y_offset = (Pattern.Units IS VUNIT::USERSPACE) ? 0 : Bounds.top;
+ const double c_width = (Pattern.Units IS VUNIT::USERSPACE) ? ViewWidth : Bounds.width();
+ const double c_height = (Pattern.Units IS VUNIT::USERSPACE) ? ViewHeight : Bounds.height();
+ const double x_offset = (Pattern.Units IS VUNIT::USERSPACE) ? 0 : Bounds.left;
+ const double y_offset = (Pattern.Units IS VUNIT::USERSPACE) ? 0 : Bounds.top;
Path->approximation_scale(Transform.scale());
if (Pattern.Units IS VUNIT::USERSPACE) { // Use fixed coordinates specified in the pattern.
- DOUBLE dwidth, dheight;
+ double dwidth, dheight;
if (dmf::hasScaledWidth(Pattern.Dimensions)) dwidth = c_width * Pattern.Width;
else if (dmf::hasWidth(Pattern.Dimensions)) dwidth = Pattern.Width;
else dwidth = 1;
@@ -470,7 +482,7 @@ static void fill_pattern(VectorState &State, const TClipRectangle &Bound
// BOUNDING_BOX. The pattern (x,y) is an optional offset applied to the base position of the vector's
// path. The area is relative to the vector's bounds.
- DOUBLE dwidth, dheight;
+ double dwidth, dheight;
if (dmf::hasScaledWidth(Pattern.Dimensions)) dwidth = Pattern.Width * c_width;
else if (dmf::hasWidth(Pattern.Dimensions)) {
@@ -508,7 +520,7 @@ static void fill_pattern(VectorState &State, const TClipRectangle &Bound
agg::trans_affine transform;
- DOUBLE dx, dy;
+ double dx, dy;
if (dmf::hasScaledX(Pattern.Dimensions)) dx = x_offset + (c_width * Pattern.X);
else if (dmf::hasX(Pattern.Dimensions)) dx = x_offset + Pattern.X;
else dx = x_offset;
diff --git a/src/vector/vector.h b/src/vector/vector.h
index 7a69215d..59b5c80c 100644
--- a/src/vector/vector.h
+++ b/src/vector/vector.h
@@ -323,6 +323,9 @@ class extVectorGradient : public objVectorGradient {
STRING ID;
LONG NumericID;
WORD ChangeCounter;
+ DOUBLE Angle;
+ DOUBLE Length;
+ bool CalcAngle; // True if the Angle/Length values require recalculation.
};
class extVectorPattern : public objVectorPattern {