Skip to content
GitLab
Menu
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
ImportedProjects
SVG
Commits
1585c700
Commit
1585c700
authored
Sep 23, 2014
by
Ritch Melton
Browse files
merged
parents
cc4f2940
1818255b
Changes
107
Show whitespace changes
Inline
Side-by-side
Source/Filter Effects/feColourMatrix/SvgColourMatrixType.cs
View file @
1585c700
...
...
@@ -3,7 +3,7 @@ using System.Collections.Generic;
using
System.Linq
;
using
System.Text
;
namespace
Svg.Filter
_
Effects
.feColourMatrix
namespace
Svg.FilterEffects
{
public
enum
SvgColourMatrixType
{
...
...
Source/Filter Effects/feGaussianBlur/SvgGaussianBlur.cs
View file @
1585c700
...
...
@@ -67,7 +67,10 @@ namespace Svg.FilterEffects
public
Bitmap
Apply
(
Image
inputImage
)
{
using
(
RawBitmap
src
=
new
RawBitmap
(
new
Bitmap
(
inputImage
)))
var
bitmapSrc
=
inputImage
as
Bitmap
;
if
(
bitmapSrc
==
null
)
bitmapSrc
=
new
Bitmap
(
inputImage
);
using
(
RawBitmap
src
=
new
RawBitmap
(
bitmapSrc
))
{
using
(
RawBitmap
dest
=
new
RawBitmap
(
new
Bitmap
(
inputImage
.
Width
,
inputImage
.
Height
)))
{
...
...
@@ -250,11 +253,11 @@ namespace Svg.FilterEffects
public
override
Bitmap
Process
()
public
override
void
Process
(
ImageBuffer
buffer
)
{
//Todo
return
n
ul
l
;
var
inputImage
=
buffer
[
this
.
Input
];
var
result
=
Apply
(
inputImage
);
buffer
[
this
.
Result
]
=
res
ul
t
;
}
...
...
Source/Filter Effects/feMerge/SvgMerge.cs
View file @
1585c700
...
...
@@ -5,44 +5,34 @@ using System.Text;
using
System.Drawing
;
using
System.Drawing.Drawing2D
;
using
System.Drawing.Imaging
;
using
System.Linq
;
namespace
Svg.FilterEffects
{
[
SvgElement
(
"feMerge"
)]
public
class
SvgMerge
:
SvgFilterPrimitive
{
public
StringCollection
MergeResults
{
get
;
private
set
;
}
public
SvgMerge
()
public
override
void
Process
(
ImageBuffer
buffer
)
{
MergeResults
=
new
StringCollection
();
}
public
override
Bitmap
Process
(
)
var
children
=
this
.
Children
.
OfType
<
SvgMergeNode
>().
ToList
();
var
inputImage
=
buffer
[
children
.
First
().
Input
];
var
result
=
new
Bitmap
(
inputImage
.
Width
,
inputImage
.
Height
);
using
(
var
g
=
Graphics
.
FromImage
(
result
)
)
{
//Todo
//Bitmap merged = new Bitmap((int)this.Owner.Width.Value, (int)this.Owner.Height.Value);
//Graphics mergedGraphics = Graphics.FromImage(merged);
//foreach (string resultId in this.MergeResults)
//{
// mergedGraphics.DrawImageUnscaled(this.Owner.Results[resultId](), new Point(0, 0));
//}
//mergedGraphics.Save();
//mergedGraphics.Dispose();
//results.Add(this.Result, () => merged);
return
null
;
foreach
(
var
child
in
children
)
{
g
.
DrawImage
(
buffer
[
child
.
Input
],
new
Rectangle
(
0
,
0
,
inputImage
.
Width
,
inputImage
.
Height
),
0
,
0
,
inputImage
.
Width
,
inputImage
.
Height
,
GraphicsUnit
.
Pixel
);
}
g
.
Flush
();
}
result
.
Save
(
@"C:\test.png"
);
buffer
[
this
.
Result
]
=
result
;
}
public
override
SvgElement
DeepCopy
()
{
throw
new
NotImplementedException
();
return
DeepCopy
<
SvgMerge
>
();
}
}
...
...
Source/Filter Effects/feMerge/SvgMergeNode.cs
View file @
1585c700
...
...
@@ -10,13 +10,13 @@ namespace Svg.FilterEffects
{
[
SvgElement
(
"feMergeNode"
)]
public
class
SvgMergeNode
:
Svg
FilterPrimitive
public
class
SvgMergeNode
:
Svg
Element
{
public
override
Bitmap
Process
()
[
SvgAttribute
(
"in"
)]
public
string
Input
{
//Todo
return
null
;
get
{
return
this
.
Attributes
.
GetAttribute
<
string
>(
"in"
);
}
set
{
this
.
Attributes
[
"in"
]
=
value
;
}
}
public
override
SvgElement
DeepCopy
()
...
...
Source/Filter Effects/feOffset/SvgOffset.cs
View file @
1585c700
using
System
;
using
System.Drawing
;
using
System.Collections.Generic
;
using
Svg.Filter_Effects.feColourMatrix
;
namespace
Svg.FilterEffects
{
...
...
@@ -28,13 +27,27 @@ namespace Svg.FilterEffects
/// Note: this is not used in calculations to bitmap - used only to allow for svg xml output
/// </summary>
[
SvgAttribute
(
"dy"
)]
public
string
Dy
{
get
;
set
;
}
public
SvgUnit
Dy
{
get
;
set
;
}
public
override
Bitmap
Process
()
public
override
void
Process
(
ImageBuffer
buffer
)
{
return
null
;
var
inputImage
=
buffer
[
this
.
Input
];
var
result
=
new
Bitmap
(
inputImage
.
Width
,
inputImage
.
Height
);
var
pts
=
new
PointF
[]
{
new
PointF
(
this
.
Dx
.
ToDeviceValue
(
null
,
UnitRenderingType
.
Horizontal
,
null
),
this
.
Dy
.
ToDeviceValue
(
null
,
UnitRenderingType
.
Vertical
,
null
))
};
buffer
.
Transform
.
TransformVectors
(
pts
);
using
(
var
g
=
Graphics
.
FromImage
(
result
))
{
g
.
DrawImage
(
inputImage
,
new
Rectangle
((
int
)
pts
[
0
].
X
,
(
int
)
pts
[
0
].
Y
,
inputImage
.
Width
,
inputImage
.
Height
),
0
,
0
,
inputImage
.
Width
,
inputImage
.
Height
,
GraphicsUnit
.
Pixel
);
g
.
Flush
();
}
buffer
[
this
.
Result
]
=
result
;
}
...
...
Source/Painting/EnumConverters.cs
View file @
1585c700
...
...
@@ -137,6 +137,23 @@ namespace Svg
}
}
public
sealed
class
SvgCoordinateUnitsConverter
:
EnumBaseConverter
<
SvgCoordinateUnits
>
{
public
override
object
ConvertFrom
(
ITypeDescriptorContext
context
,
CultureInfo
culture
,
object
value
)
{
if
(
value
==
null
||
value
.
ToString
()
==
""
)
return
SvgCoordinateUnits
.
Inherit
;
return
base
.
ConvertFrom
(
context
,
culture
,
value
);
}
public
override
object
ConvertTo
(
ITypeDescriptorContext
context
,
CultureInfo
culture
,
object
value
,
Type
destinationType
)
{
if
(
destinationType
==
typeof
(
string
)
&&
value
is
SvgCoordinateUnits
&&
(
SvgCoordinateUnits
)
value
==
SvgCoordinateUnits
.
Inherit
)
{
return
null
;
}
return
base
.
ConvertTo
(
context
,
culture
,
value
,
destinationType
);
}
}
public
sealed
class
SvgTextDecorationConverter
:
EnumBaseConverter
<
SvgTextDecoration
>
{
public
override
object
ConvertFrom
(
ITypeDescriptorContext
context
,
CultureInfo
culture
,
object
value
)
...
...
Source/Painting/ISvgStylable.cs
View file @
1585c700
...
...
@@ -19,6 +19,6 @@ namespace Svg
float
StrokeMiterLimit
{
get
;
set
;
}
SvgUnitCollection
StrokeDashArray
{
get
;
set
;
}
SvgUnit
StrokeDashOffset
{
get
;
set
;
}
GraphicsPath
Path
(
SvgRenderer
renderer
);
GraphicsPath
Path
(
I
SvgRenderer
renderer
);
}
}
\ No newline at end of file
Source/Painting/SvgColourServer.cs
View file @
1585c700
...
...
@@ -35,7 +35,7 @@ namespace Svg
set
{
this
.
_colour
=
value
;
}
}
public
override
Brush
GetBrush
(
SvgVisualElement
styleOwner
,
SvgRenderer
renderer
,
float
opacity
)
public
override
Brush
GetBrush
(
SvgVisualElement
styleOwner
,
I
SvgRenderer
renderer
,
float
opacity
,
bool
forStroke
=
false
)
{
//is none?
if
(
this
==
SvgPaintServer
.
None
)
return
new
SolidBrush
(
System
.
Drawing
.
Color
.
Transparent
);
...
...
Source/Painting/SvgDeferredPaintServer.cs
View file @
1585c700
...
...
@@ -2,6 +2,7 @@
using
System.Collections.Generic
;
using
System.Linq
;
using
System.Text
;
using
System.Drawing
;
namespace
Svg
{
...
...
@@ -44,10 +45,10 @@ namespace Svg
}
}
public
override
System
.
Drawing
.
Brush
GetBrush
(
SvgVisualElement
styleOwner
,
SvgRenderer
renderer
,
float
opacity
)
public
override
Brush
GetBrush
(
SvgVisualElement
styleOwner
,
I
SvgRenderer
renderer
,
float
opacity
,
bool
forStroke
=
false
)
{
EnsureServer
(
styleOwner
);
return
_concreteServer
.
GetBrush
(
styleOwner
,
renderer
,
opacity
);
return
_concreteServer
.
GetBrush
(
styleOwner
,
renderer
,
opacity
,
forStroke
);
}
public
override
SvgElement
DeepCopy
()
...
...
Source/Painting/SvgFallbackPaintServer .cs
0 → 100644
View file @
1585c700
using
System
;
using
System.Collections.Generic
;
using
System.Linq
;
using
System.Text
;
using
System.Drawing
;
namespace
Svg
{
/// <summary>
/// A wrapper for a paint server has a fallback if the primary server doesn't work.
/// </summary>
public
class
SvgFallbackPaintServer
:
SvgPaintServer
{
private
IEnumerable
<
SvgPaintServer
>
_fallbacks
;
private
SvgPaintServer
_primary
;
public
SvgFallbackPaintServer
()
:
base
()
{
}
public
SvgFallbackPaintServer
(
SvgPaintServer
primary
,
IEnumerable
<
SvgPaintServer
>
fallbacks
)
:
this
()
{
_fallbacks
=
fallbacks
;
_primary
=
primary
;
}
public
override
Brush
GetBrush
(
SvgVisualElement
styleOwner
,
ISvgRenderer
renderer
,
float
opacity
,
bool
forStroke
=
false
)
{
try
{
_primary
.
GetCallback
=
()
=>
_fallbacks
.
FirstOrDefault
();
return
_primary
.
GetBrush
(
styleOwner
,
renderer
,
opacity
,
forStroke
);
}
finally
{
_primary
.
GetCallback
=
null
;
}
}
public
override
SvgElement
DeepCopy
()
{
return
base
.
DeepCopy
<
SvgFallbackPaintServer
>();
}
public
override
SvgElement
DeepCopy
<
T
>()
{
var
newObj
=
base
.
DeepCopy
<
T
>()
as
SvgFallbackPaintServer
;
newObj
.
_fallbacks
=
this
.
_fallbacks
;
newObj
.
_primary
=
this
.
_primary
;
return
newObj
;
}
}
}
Source/Painting/SvgGradientServer.cs
View file @
1585c700
...
...
@@ -88,7 +88,7 @@ namespace Svg
/// <summary>
/// Gets or sets another gradient fill from which to inherit the stops from.
/// </summary>
[
SvgAttribute
(
"href"
)]
[
SvgAttribute
(
"href"
,
SvgAttributeAttribute
.
XLinkNamespace
)]
public
SvgPaintServer
InheritGradient
{
get
{
return
this
.
_inheritGradient
;
}
...
...
@@ -101,17 +101,11 @@ namespace Svg
[
SvgAttribute
(
"gradientTransform"
)]
public
SvgTransformCollection
GradientTransform
{
get
{
return
(
this
.
Attributes
.
GetAttribute
<
SvgTransformCollection
>(
"gradientTransform"
));
}
set
{
this
.
Attributes
[
"gradientTransform"
]
=
value
;
}
get
{
return
(
this
.
Attributes
.
GetAttribute
<
SvgTransformCollection
>(
"gradientTransform"
));
}
set
{
this
.
Attributes
[
"gradientTransform"
]
=
value
;
}
}
pr
ivate
Matrix
EffectiveGradientTransform
pr
otected
Matrix
EffectiveGradientTransform
{
get
{
...
...
@@ -130,7 +124,7 @@ namespace Svg
/// </summary>
/// <param name="owner">The parent <see cref="SvgVisualElement"/>.</param>
/// <param name="opacity">The opacity of the colour blend.</param>
protected
ColorBlend
GetColorBlend
(
SvgRenderer
renderer
,
float
opacity
,
bool
radial
)
protected
ColorBlend
GetColorBlend
(
I
SvgRenderer
renderer
,
float
opacity
,
bool
radial
)
{
int
colourBlends
=
this
.
Stops
.
Count
;
bool
insertStart
=
false
;
...
...
@@ -184,9 +178,9 @@ namespace Svg
for
(
int
i
=
0
;
i
<
colourBlends
;
i
++)
{
var
currentStop
=
this
.
Stops
[
radial
?
this
.
Stops
.
Count
-
1
-
actualStops
:
actualStops
];
var
boundWidth
=
renderer
.
Boundable
().
Bounds
.
Width
;
var
boundWidth
=
renderer
.
Get
Boundable
().
Bounds
.
Width
;
mergedOpacity
=
opacity
*
currentStop
.
Opacity
;
mergedOpacity
=
opacity
*
currentStop
.
Get
Opacity
()
;
position
=
radial
?
1
-
(
currentStop
.
Offset
.
ToDeviceValue
(
renderer
,
UnitRenderingType
.
Horizontal
,
this
)
/
boundWidth
)
...
...
@@ -229,24 +223,6 @@ namespace Svg
}
}
protected
PointF
TransformPoint
(
PointF
originalPoint
)
{
var
newPoint
=
new
[]
{
originalPoint
};
EffectiveGradientTransform
.
TransformPoints
(
newPoint
);
return
newPoint
[
0
];
}
protected
PointF
TransformVector
(
PointF
originalVector
)
{
var
newVector
=
new
[]
{
originalVector
};
EffectiveGradientTransform
.
TransformVectors
(
newVector
);
return
newVector
[
0
];
}
protected
static
double
CalculateDistance
(
PointF
first
,
PointF
second
)
{
return
Math
.
Sqrt
(
Math
.
Pow
(
first
.
X
-
second
.
X
,
2
)
+
Math
.
Pow
(
first
.
Y
-
second
.
Y
,
2
));
...
...
Source/Painting/SvgGradientStop.cs
View file @
1585c700
...
...
@@ -13,8 +13,6 @@ namespace Svg
public
class
SvgGradientStop
:
SvgElement
{
private
SvgUnit
_offset
;
private
SvgPaintServer
_colour
;
private
float
_opacity
;
/// <summary>
/// Gets or sets the offset, i.e. where the stop begins from the beginning, of the gradient stop.
...
...
@@ -59,20 +57,31 @@ namespace Svg
/// </summary>
[
SvgAttribute
(
"stop-color"
)]
[
TypeConverter
(
typeof
(
SvgPaintServerFactory
))]
public
SvgPaintServer
Colo
u
r
public
SvgPaintServer
Stop
Color
{
get
{
return
this
.
_colour
;
}
set
{
this
.
_colour
=
value
;
}
get
{
var
direct
=
this
.
Attributes
.
GetAttribute
<
SvgPaintServer
>(
"stop-color"
,
SvgColourServer
.
NotSet
);
if
(
direct
==
SvgColourServer
.
Inherit
)
return
this
.
Attributes
[
"stop-color"
]
as
SvgPaintServer
??
SvgColourServer
.
NotSet
;
return
direct
;
}
set
{
this
.
Attributes
[
"stop-color"
]
=
value
;
}
}
/// <summary>
/// Gets or sets the opacity of the gradient stop (0-1).
/// </summary>
[
SvgAttribute
(
"stop-opacity"
)]
public
float
Opacity
public
string
Opacity
{
get
{
return
this
.
Attributes
[
"stop-opacity"
]
as
string
;
}
set
{
this
.
Attributes
[
"stop-opacity"
]
=
value
;
}
}
public
float
GetOpacity
()
{
get
{
return
this
.
_o
pacity
;
}
s
et
{
this
.
_opacity
=
value
;
}
var
opacity
=
this
.
O
pacity
;
r
et
urn
string
.
IsNullOrEmpty
(
opacity
)
?
1.0f
:
float
.
Parse
(
opacity
);
}
/// <summary>
...
...
@@ -81,8 +90,6 @@ namespace Svg
public
SvgGradientStop
()
{
this
.
_offset
=
new
SvgUnit
(
0.0f
);
this
.
_colour
=
SvgColourServer
.
NotSet
;
this
.
_opacity
=
1.0f
;
}
/// <summary>
...
...
@@ -93,13 +100,11 @@ namespace Svg
public
SvgGradientStop
(
SvgUnit
offset
,
Color
colour
)
{
this
.
_offset
=
offset
;
this
.
_colour
=
new
SvgColourServer
(
colour
);
this
.
_opacity
=
1.0f
;
}
public
Color
GetColor
(
SvgElement
parent
)
{
var
core
=
SvgDeferredPaintServer
.
TryGet
<
SvgColourServer
>(
_c
olo
u
r
,
parent
);
var
core
=
SvgDeferredPaintServer
.
TryGet
<
SvgColourServer
>(
this
.
StopC
olor
,
parent
);
if
(
core
==
null
)
throw
new
InvalidOperationException
(
"Invalid paint server for gradient stop detected."
);
return
core
.
Colour
;
}
...
...
@@ -113,9 +118,6 @@ namespace Svg
{
var
newObj
=
base
.
DeepCopy
<
T
>()
as
SvgGradientStop
;
newObj
.
Offset
=
this
.
Offset
;
newObj
.
Colour
=
this
.
Colour
;
newObj
.
Opacity
=
this
.
Opacity
;
return
newObj
;
}
}
...
...
Source/Painting/SvgLinearGradientServer.cs
View file @
1585c700
...
...
@@ -79,36 +79,94 @@ namespace Svg
Y2
=
new
SvgUnit
(
SvgUnitType
.
Percentage
,
0F
);
}
public
override
Brush
GetBrush
(
SvgVisualElement
renderingElement
,
SvgRenderer
renderer
,
float
opacity
)
public
override
Brush
GetBrush
(
SvgVisualElement
renderingElement
,
I
SvgRenderer
renderer
,
float
opacity
,
bool
forStroke
=
false
)
{
LoadStops
(
renderingElement
);
if
(
IsInvalid
)
if
(
this
.
Stops
.
Count
<
1
)
return
null
;
if
(
this
.
Stops
.
Count
==
1
)
{
return
null
;
var
stopColor
=
this
.
Stops
[
0
].
GetColor
(
renderingElement
);
int
alpha
=
(
int
)((
opacity
*
(
stopColor
.
A
/
255.0f
)
)
*
255
);
Color
colour
=
System
.
Drawing
.
Color
.
FromArgb
(
alpha
,
stopColor
);
return
new
SolidBrush
(
colour
);
}
try
{
if
(
this
.
GradientUnits
==
SvgCoordinateUnits
.
ObjectBoundingBox
)
renderer
.
Boundable
(
renderingElement
);
if
(
this
.
GradientUnits
==
SvgCoordinateUnits
.
ObjectBoundingBox
)
renderer
.
Set
Boundable
(
renderingElement
);
var
specifiedStart
=
CalculateStart
(
renderer
);
var
specifiedEnd
=
CalculateEnd
(
renderer
);
var
points
=
new
PointF
[]
{
SvgUnit
.
GetDevicePoint
(
NormalizeUnit
(
this
.
X1
),
NormalizeUnit
(
this
.
Y1
),
renderer
,
this
),
SvgUnit
.
GetDevicePoint
(
NormalizeUnit
(
this
.
X2
),
NormalizeUnit
(
this
.
Y2
),
renderer
,
this
)
};
var
effectiveStart
=
specifiedStart
;
var
effectiveEnd
=
specifiedEnd
;
var
bounds
=
renderer
.
GetBoundable
().
Bounds
;
if
(
bounds
.
Width
<=
0
||
bounds
.
Height
<=
0
)
{
if
(
this
.
GetCallback
!=
null
)
return
GetCallback
().
GetBrush
(
renderingElement
,
renderer
,
opacity
,
forStroke
);
return
null
;
}
using
(
var
transform
=
EffectiveGradientTransform
)
{
var
midPoint
=
new
PointF
((
points
[
0
].
X
+
points
[
1
].
X
)
/
2
,
(
points
[
0
].
Y
+
points
[
1
].
Y
)
/
2
);
transform
.
Translate
(
bounds
.
X
,
bounds
.
Y
,
MatrixOrder
.
Prepend
);
if
(
this
.
GradientUnits
==
SvgCoordinateUnits
.
ObjectBoundingBox
)
{
// Transform a normal (i.e. perpendicular line) according to the transform
transform
.
Scale
(
bounds
.
Width
,
bounds
.
Height
,
MatrixOrder
.
Prepend
);
transform
.
RotateAt
(-
90.0f
,
midPoint
,
MatrixOrder
.
Prepend
);
}
transform
.
TransformPoints
(
points
);
}
if
(
NeedToExpandGradient
(
renderingElement
,
specifiedStart
,
specifiedEnd
)
)
if
(
this
.
GradientUnits
==
SvgCoordinateUnits
.
ObjectBoundingBox
)
{
var
expansion
=
ExpandGradient
(
renderingElement
,
specifiedStart
,
specifiedEnd
);
// Transform the normal line back to a line such that the gradient still starts in the correct corners, but
// has the proper normal vector based on the transforms. If you work out the geometry, these formulas should work.
var
midPoint
=
new
PointF
((
points
[
0
].
X
+
points
[
1
].
X
)
/
2
,
(
points
[
0
].
Y
+
points
[
1
].
Y
)
/
2
);
var
dy
=
(
points
[
1
].
Y
-
points
[
0
].
Y
);
var
dx
=
(
points
[
1
].
X
-
points
[
0
].
X
);
var
x2
=
points
[
0
].
X
;
var
y2
=
points
[
1
].
Y
;
if
(
Math
.
Round
(
dx
,
4
)
==
0
)
{
points
[
0
]
=
new
PointF
(
midPoint
.
X
+
dy
/
2
*
bounds
.
Width
/
bounds
.
Height
,
midPoint
.
Y
);
points
[
1
]
=
new
PointF
(
midPoint
.
X
-
dy
/
2
*
bounds
.
Width
/
bounds
.
Height
,
midPoint
.
Y
);
}
else
if
(
Math
.
Round
(
dy
,
4
)
==
0
)
{
points
[
0
]
=
new
PointF
(
midPoint
.
X
,
midPoint
.
Y
-
dx
/
2
*
bounds
.
Height
/
bounds
.
Width
);
points
[
1
]
=
new
PointF
(
midPoint
.
X
,
midPoint
.
Y
+
dx
/
2
*
bounds
.
Height
/
bounds
.
Width
);
;
}
else
{
var
startX
=
(
float
)((
dy
*
dx
*
(
midPoint
.
Y
-
y2
)
+
Math
.
Pow
(
dx
,
2
)
*
midPoint
.
X
+
Math
.
Pow
(
dy
,
2
)
*
x2
)
/
(
Math
.
Pow
(
dx
,
2
)
+
Math
.
Pow
(
dy
,
2
)));
var
startY
=
dy
*
(
startX
-
x2
)
/
dx
+
y2
;
points
[
0
]
=
new
PointF
(
startX
,
startY
);
points
[
1
]
=
new
PointF
(
midPoint
.
X
+
(
midPoint
.
X
-
startX
),
midPoint
.
Y
+
(
midPoint
.
Y
-
startY
));
}
}
var
effectiveStart
=
points
[
0
];
var
effectiveEnd
=
points
[
1
];
if
(
PointsToMove
(
renderingElement
,
points
[
0
],
points
[
1
])
>
LinePoints
.
None
)
{
var
expansion
=
ExpandGradient
(
renderingElement
,
points
[
0
],
points
[
1
]);
effectiveStart
=
expansion
.
StartPoint
;
effectiveEnd
=
expansion
.
EndPoint
;
}
return
new
LinearGradientBrush
(
effectiveStart
,
effectiveEnd
,
System
.
Drawing
.
Color
.
Transparent
,
System
.
Drawing
.
Color
.
Transparent
)
var
result
=
new
LinearGradientBrush
(
effectiveStart
,
effectiveEnd
,
System
.
Drawing
.
Color
.
Transparent
,
System
.
Drawing
.
Color
.
Transparent
)
{
InterpolationColors
=
CalculateColorBlend
(
renderer
,
opacity
,
specifiedStart
,
effectiveStart
,
specifiedEnd
,
effectiveEnd
),
InterpolationColors
=
CalculateColorBlend
(
renderer
,
opacity
,
points
[
0
]
,
effectiveStart
,
points
[
1
]
,
effectiveEnd
),
WrapMode
=
WrapMode
.
TileFlipX
};
return
result
;
}
finally
{
...
...
@@ -116,19 +174,36 @@ namespace Svg
}
}
private
PointF
CalculateStart
(
SvgRenderer
renderer
)
private
SvgUnit
NormalizeUnit
(
SvgUnit
orig
)
{
return
TransformPoint
(
SvgUnit
.
GetDevicePointOffset
(
this
.
X1
,
this
.
Y1
,
renderer
,
this
));
return
(
orig
.
Type
==
SvgUnitType
.
Percentage
&&
this
.
GradientUnits
==
SvgCoordinateUnits
.
ObjectBoundingBox
?
new
SvgUnit
(
SvgUnitType
.
User
,
orig
.
Value
/
100
)
:
orig
);
}
private
PointF
CalculateEnd
(
SvgRenderer
renderer
)
[
Flags
]
private
enum
LinePoints
{
return
TransformPoint
(
SvgUnit
.
GetDevicePointOffset
(
this
.
X2
,
this
.
Y2
,
renderer
,
this
));
None
=
0
,
Start
=
1
,
End
=
2
}
private
bool
NeedToExpandGradient
(
ISvgBoundable
boundable
,
PointF
specifiedStart
,
PointF
specifiedEnd
)
private
LinePoints
PointsToMove
(
ISvgBoundable
boundable
,
PointF
specifiedStart
,
PointF
specifiedEnd
)
{
return
SpreadMethod
==
SvgGradientSpreadMethod
.
Pad
&&
(
boundable
.
Bounds
.
Contains
(
specifiedStart
)
||
boundable
.
Bounds
.
Contains
(
specifiedEnd
));
var
bounds
=
boundable
.
Bounds
;
if
(
specifiedStart
.
X
==
specifiedEnd
.
X
)
{
return
(
bounds
.
Top
<
specifiedStart
.
Y
&&
specifiedStart
.
Y
<
bounds
.
Bottom
?
LinePoints
.
Start
:
LinePoints
.
None
)
|
(
bounds
.
Top
<
specifiedEnd
.
Y
&&
specifiedEnd
.
Y
<
bounds
.
Bottom
?
LinePoints
.
End
:
LinePoints
.
None
);
}
else
if
(
specifiedStart
.
Y
==
specifiedEnd
.
Y
)
{
return
(
bounds
.
Left
<
specifiedStart
.
X
&&
specifiedStart
.
X
<
bounds
.
Right
?
LinePoints
.
Start
:
LinePoints
.
None
)
|
(
bounds
.
Left
<
specifiedEnd
.
X
&&
specifiedEnd
.
X
<
bounds
.
Right
?
LinePoints
.
End
:
LinePoints
.
None
);
}
return
(
boundable
.
Bounds
.
Contains
(
specifiedStart
)
?
LinePoints
.
Start
:
LinePoints
.
None
)
|
(
boundable
.
Bounds
.
Contains
(
specifiedEnd
)
?
LinePoints
.
End
:
LinePoints
.
None
);
}
public
struct
GradientPoints
...
...
@@ -145,44 +220,98 @@ namespace Svg
private
GradientPoints
ExpandGradient
(
ISvgBoundable
boundable
,
PointF
specifiedStart
,
PointF
specifiedEnd
)
{
if
(!
NeedToExpandGradient
(
boundable
,
specifiedStart
,
specifiedEnd
))
var
pointsToMove
=
PointsToMove
(
boundable
,
specifiedStart
,
specifiedEnd
);
if
(
pointsToMove
==
LinePoints
.
None
)
{
Debug
.
Fail
(
"Unexpectedly expanding gradient when not needed!"
);
return
new
GradientPoints
(
specifiedStart
,
specifiedEnd
);
}
var
specifiedLength
=
CalculateDistance
(
specifiedStart
,
specifiedEnd
);
var
specifiedUnitVector
=
new
PointF
((
specifiedEnd
.
X
-
specifiedStart
.
X
)
/
(
float
)
specifiedLength
,
(
specifiedEnd
.
Y
-
specifiedStart
.
Y
)
/
(
float
)
specifiedLength
);
var
bounds
=
boundable
.
Bounds
;
var
effectiveStart
=
specifiedStart
;
var
effectiveEnd
=
specifiedEnd
;
var
intersectionPoints
=
CandidateIntersections
(
bounds
,
specifiedStart
,
specifiedEnd
);
var
elementDiagonal
=
(
float
)
CalculateDistance
(
new
PointF
(
boundable
.
Bounds
.
Left
,
boundable
.
Bounds
.
Top
),
new
PointF
(
boundable
.
Bounds
.
Right
,
boundable
.
Bounds
.
Bottom
)
);
Debug
.
Assert
(
intersectionPoints
.
Count
==
2
,
"Unanticipated number of intersection points"
);
var
expandedStart
=
MovePointAlongVector
(
effectiveStart
,
specifiedUnitVector
,
-
elementDiagonal
);
var
expandedEnd
=
MovePointAlongVector
(
effectiveEnd
,
specifiedUnitVector
,
elementDiagonal
);
if
(!(
Math
.
Sign
(
intersectionPoints
[
1
].
X
-
intersectionPoints
[
0
].
X
)
==
Math
.
Sign
(
specifiedEnd
.
X
-
specifiedStart
.
X
)
&&
Math
.
Sign
(
intersectionPoints
[
1
].
Y
-
intersectionPoints
[
0
].
Y
)
==
Math
.
Sign
(
specifiedEnd
.
Y
-
specifiedStart
.
Y
)))
{
intersectionPoints
=
intersectionPoints
.
Reverse
().
ToList
();
}
var
intersectionPoints
=
new
LineF
(
expandedStart
.
X
,
expandedStart
.
Y
,
expandedEnd
.
X
,
expandedEnd
.
Y
).
Intersection
(
boundable
.
Bounds
);
if
((
pointsToMove
&
LinePoints
.
Start
)
>
0
)
effectiveStart
=
intersectionPoints
[
0
];
if
((
pointsToMove
&
LinePoints
.
End
)
>
0
)
effectiveEnd
=
intersectionPoints
[
1
];
if
(
boundable
.
Bounds
.
Contains
(
specifiedStart
)
)
switch
(
SpreadMethod
)
{
effectiveStart
=
CalculateClosestIntersectionPoint
(
expandedStart
,
intersectionPoints
);
case
SvgGradientSpreadMethod
.
Reflect
:
case
SvgGradientSpreadMethod
.
Repeat
:
var
specifiedLength
=
CalculateDistance
(
specifiedStart
,
specifiedEnd
);
var
specifiedUnitVector
=
new
PointF
((
specifiedEnd
.
X
-
specifiedStart
.
X
)
/
(
float
)
specifiedLength
,
(
specifiedEnd
.
Y
-
specifiedStart
.
Y
)
/
(
float
)
specifiedLength
);
var
oppUnitVector
=
new
PointF
(-
specifiedUnitVector
.
X
,
-
specifiedUnitVector
.
Y
);
effectiveStart
=
MovePointAlongVector
(
effectiveStart
,
specifiedUnitVector
,
-
1
);
var
startExtend
=
(
float
)(
Math
.
Ceiling
(
CalculateDistance
(
effectiveStart
,
specifiedStart
)
/
specifiedLength
)
*
specifiedLength
);
effectiveStart
=
MovePointAlongVector
(
specifiedStart
,
oppUnitVector
,
startExtend
);
var
endExtend
=
(
float
)(
Math
.
Ceiling
(
CalculateDistance
(
effectiveEnd
,
specifiedEnd
)
/
specifiedLength
)
*
specifiedLength
);
effectiveEnd
=
MovePointAlongVector
(
specifiedEnd
,
specifiedUnitVector
,
endExtend
);
break
;
}
if
(
boundable
.
Bounds
.
Contains
(
specifiedEnd
))
{
effectiveEnd
=
CalculateClosestIntersectionPoint
(
effectiveEnd
,
intersectionPoints
);
return
new
GradientPoints
(
effectiveStart
,
effectiveEnd
);
}
effectiveEnd
=
MovePointAlongVector
(
effectiveEnd
,
specifiedUnitVector
,
1
);
private
IList
<
PointF
>
CandidateIntersections
(
RectangleF
bounds
,
PointF
p1
,
PointF
p2
)
{
var
results
=
new
List
<
PointF
>();
if
(
Math
.
Round
(
Math
.
Abs
(
p1
.
Y
-
p2
.
Y
),
4
)
==
0
)
{
results
.
Add
(
new
PointF
(
bounds
.
Left
,
p1
.
Y
));
results
.
Add
(
new
PointF
(
bounds
.
Right
,
p1
.
Y
));
}
else
if
(
Math
.
Round
(
Math
.
Abs
(
p1
.
X
-
p2
.
X
),
4
)
==
0
)
{
results
.
Add
(
new
PointF
(
p1
.
X
,
bounds
.
Top
));
results
.
Add
(
new
PointF
(
p1
.
X
,
bounds
.
Bottom
));
}
else
{
PointF
candidate
;
// Save some effort and duplication in the trivial case
if
((
p1
.
X
==
bounds
.
Left
||
p1
.
X
==
bounds
.
Right
)
&&
(
p1
.
Y
==
bounds
.
Top
||
p1
.
Y
==
bounds
.
Bottom
))
{
results
.
Add
(
p1
);
}
else
{
candidate
=
new
PointF
(
bounds
.
Left
,
(
p2
.
Y
-
p1
.
Y
)
/
(
p2
.
X
-
p1
.
X
)
*
(
bounds
.
Left
-
p1
.
X
)
+
p1
.
Y
);
if
(
bounds
.
Top
<=
candidate
.
Y
&&
candidate
.
Y
<=
bounds
.
Bottom
)
results
.
Add
(
candidate
);
candidate
=
new
PointF
(
bounds
.
Right
,
(
p2
.
Y
-
p1
.
Y
)
/
(
p2
.
X
-
p1
.
X
)
*
(
bounds
.
Right
-
p1
.
X
)
+
p1
.
Y
);
if
(
bounds
.
Top
<=
candidate
.
Y
&&
candidate
.
Y
<=
bounds
.
Bottom
)
results
.
Add
(
candidate
);
}
if
((
p2
.
X
==
bounds
.
Left
||
p2
.
X
==
bounds
.
Right
)
&&
(
p2
.
Y
==
bounds
.
Top
||
p2
.
Y
==
bounds
.
Bottom
))
{
results
.
Add
(
p2
);
}
else
{
candidate
=
new
PointF
((
bounds
.
Top
-
p1
.
Y
)
/
(
p2
.
Y
-
p1
.
Y
)
*
(
p2
.
X
-
p1
.
X
)
+
p1
.
X
,
bounds
.
Top
);
if
(
bounds
.
Left
<=
candidate
.
X
&&
candidate
.
X
<=
bounds
.
Right
)
results
.
Add
(
candidate
);
candidate
=
new
PointF
((
bounds
.
Bottom
-
p1
.
Y
)
/
(
p2
.
Y
-
p1
.
Y
)
*
(
p2
.
X
-
p1
.
X
)
+
p1
.
X
,
bounds
.
Bottom
);
if
(
bounds
.
Left
<=
candidate
.
X
&&
candidate
.
X
<=
bounds
.
Right
)
results
.
Add
(
candidate
);
}
}
return
new
GradientPoints
(
effectiveStart
,
effectiveEnd
)
;
return
results
;
}
private
ColorBlend
CalculateColorBlend
(
SvgRenderer
renderer
,
float
opacity
,
PointF
specifiedStart
,
PointF
effectiveStart
,
PointF
specifiedEnd
,
PointF
effectiveEnd
)
private
ColorBlend
CalculateColorBlend
(
I
SvgRenderer
renderer
,
float
opacity
,
PointF
specifiedStart
,
PointF
effectiveStart
,
PointF
specifiedEnd
,
PointF
effectiveEnd
)
{
float
startExtend
;
float
endExtend
;
List
<
Color
>
colors
;
List
<
float
>
positions
;
var
colorBlend
=
GetColorBlend
(
renderer
,
opacity
,
false
);
var
startDelta
=
CalculateDistance
(
specifiedStart
,
effectiveStart
);
...
...
@@ -198,6 +327,80 @@ namespace Svg
var
effectiveLength
=
CalculateDistance
(
effectiveStart
,
effectiveEnd
);
switch
(
SpreadMethod
)
{
case
SvgGradientSpreadMethod
.
Reflect
:
startExtend
=
(
float
)(
Math
.
Ceiling
(
CalculateDistance
(
effectiveStart
,
specifiedStart
)
/
specifiedLength
));
endExtend
=
(
float
)(
Math
.
Ceiling
(
CalculateDistance
(
effectiveEnd
,
specifiedEnd
)
/
specifiedLength
));
colors
=
colorBlend
.
Colors
.
ToList
();
positions
=
(
from
p
in
colorBlend
.
Positions
select
p
+
startExtend
).
ToList
();
for
(
var
i
=
0
;
i
<
startExtend
;
i
++)
{
if
(
i
%
2
==
0
)
{
for
(
var
j
=
1
;
j
<
colorBlend
.
Positions
.
Length
;
j
++)
{
positions
.
Insert
(
0
,
(
float
)((
startExtend
-
1
-
i
)
+
1
-
colorBlend
.
Positions
[
j
]));
colors
.
Insert
(
0
,
colorBlend
.
Colors
[
j
]);
}
}
else
{
for
(
var
j
=
0
;
j
<
colorBlend
.
Positions
.
Length
-
1
;
j
++)
{
positions
.
Insert
(
j
,
(
float
)((
startExtend
-
1
-
i
)
+
colorBlend
.
Positions
[
j
]));
colors
.
Insert
(
j
,
colorBlend
.
Colors
[
j
]);
}
}
}
int
insertPos
;
for
(
var
i
=
0
;
i
<
endExtend
;
i
++)
{
if
(
i
%
2
==
0
)
{
insertPos
=
positions
.
Count
;
for
(
var
j
=
0
;
j
<
colorBlend
.
Positions
.
Length
-
1
;
j
++)
{
positions
.
Insert
(
insertPos
,
(
float
)((
startExtend
+
1
+
i
)
+
1
-
colorBlend
.
Positions
[
j
]));
colors
.
Insert
(
insertPos
,
colorBlend
.
Colors
[
j
]);
}
}
else
{
for
(
var
j
=
1
;
j
<
colorBlend
.
Positions
.
Length
;
j
++)
{
positions
.
Add
((
float
)((
startExtend
+
1
+
i
)
+
colorBlend
.
Positions
[
j
]));
colors
.
Add
(
colorBlend
.
Colors
[
j
]);
}
}
}
colorBlend
.
Colors
=
colors
.
ToArray
();
colorBlend
.
Positions
=
(
from
p
in
positions
select
p
/
(
startExtend
+
1
+
endExtend
)).
ToArray
();
break
;
case
SvgGradientSpreadMethod
.
Repeat
:
startExtend
=
(
float
)(
Math
.
Ceiling
(
CalculateDistance
(
effectiveStart
,
specifiedStart
)
/
specifiedLength
));
endExtend
=
(
float
)(
Math
.
Ceiling
(
CalculateDistance
(
effectiveEnd
,
specifiedEnd
)
/
specifiedLength
));
colors
=
new
List
<
Color
>();
positions
=
new
List
<
float
>();
for
(
int
i
=
0
;
i
<
startExtend
+
endExtend
+
1
;
i
++)
{
for
(
int
j
=
0
;
j
<
colorBlend
.
Positions
.
Length
;
j
++)
{
positions
.
Add
((
i
+
colorBlend
.
Positions
[
j
]
*
0.9999f
)
/
(
startExtend
+
endExtend
+
1
));
colors
.
Add
(
colorBlend
.
Colors
[
j
]);
}
}
positions
[
positions
.
Count
-
1
]
=
1.0f
;
colorBlend
.
Colors
=
colors
.
ToArray
();
colorBlend
.
Positions
=
positions
.
ToArray
();
break
;
default
:
for
(
var
i
=
0
;
i
<
colorBlend
.
Positions
.
Length
;
i
++)
{
var
originalPoint
=
MovePointAlongVector
(
specifiedStart
,
specifiedUnitVector
,
(
float
)
specifiedLength
*
colorBlend
.
Positions
[
i
]);
...
...
@@ -218,6 +421,8 @@ namespace Svg
colorBlend
.
Positions
=
colorBlend
.
Positions
.
Concat
(
new
[]
{
1F
}).
ToArray
();
colorBlend
.
Colors
=
colorBlend
.
Colors
.
Concat
(
new
[]
{
colorBlend
.
Colors
.
Last
()
}).
ToArray
();
}
break
;
}
return
colorBlend
;
}
...
...
@@ -296,48 +501,45 @@ namespace Svg
return
result
;
}
/// <remarks>http://community.topcoder.com/tc?module=Static&d1=tutorials&d2=geometry2</remarks>
private
PointF
?
Intersection
(
LineF
other
)
{
var
a1
=
Y2
-
Y1
;
var
b1
=
X1
-
X2
;
var
c1
=
X2
*
Y1
-
X1
*
Y2
;
const
int
precision
=
8
;
var
a1
=
(
double
)
Y2
-
Y1
;
var
b1
=
(
double
)
X1
-
X2
;
var
c1
=
a1
*
X1
+
b1
*
Y1
;
var
r3
=
a1
*
other
.
X1
+
b1
*
other
.
Y1
+
c1
;
var
r4
=
a1
*
other
.
X2
+
b1
*
other
.
Y2
+
c1
;
var
a2
=
(
double
)
other
.
Y2
-
other
.
Y1
;
var
b2
=
(
double
)
other
.
X1
-
other
.
X2
;
var
c2
=
a2
*
other
.
X1
+
b2
*
other
.
Y1
;
if
(
r3
!=
0
&&
r4
!=
0
&&
Math
.
Sign
(
r3
)
==
Math
.
Sign
(
r4
))
var
det
=
a1
*
b2
-
a2
*
b1
;
if
(
det
==
0
)
{
return
null
;
}
else
{
var
xi
=
(
b2
*
c1
-
b1
*
c2
)
/
det
;
var
yi
=
(
a1
*
c2
-
a2
*
c1
)
/
det
;
var
a2
=
other
.
Y2
-
other
.
Y1
;
var
b2
=
other
.
X1
-
other
.
X2
;
var
c2
=
other
.
X2
*
other
.
Y1
-
other
.
X1
*
other
.
Y2
;
var
r1
=
a2
*
X1
+
b2
*
Y1
+
c2
;
var
r2
=
a2
*
X2
+
b2
*
Y2
+
c2
;
if
(
r1
!=
0
&&
r2
!=
0
&&
Math
.
Sign
(
r1
)
=
=
Math
.
Sign
(
r2
))
if
(
Math
.
Round
(
Math
.
Min
(
X1
,
X2
),
precision
)
<=
Math
.
Round
(
xi
,
precision
)
&&
Math
.
Round
(
xi
,
precision
)
<=
Math
.
Round
(
Math
.
Max
(
X1
,
X2
),
precision
)
&&
Math
.
Round
(
Math
.
Min
(
Y1
,
Y2
),
precision
)
<=
Math
.
Round
(
yi
,
precision
)
&&
Math
.
Round
(
yi
,
precision
)
<=
Math
.
Round
(
Math
.
Max
(
Y1
,
Y2
),
precision
)
&&
Math
.
Round
(
Math
.
Min
(
other
.
X1
,
other
.
X2
),
precision
)
<=
Math
.
Round
(
xi
,
precision
)
&&
Math
.
Round
(
xi
,
precision
)
<=
Math
.
Round
(
Math
.
Max
(
other
.
X1
,
other
.
X2
),
precision
)
&&
Math
.
Round
(
Math
.
Min
(
other
.
Y1
,
other
.
Y2
),
precision
)
<=
Math
.
Round
(
yi
,
precision
)
&&
Math
.
Round
(
yi
,
precision
)
<
=
Math
.
Round
(
Math
.
Max
(
other
.
Y1
,
other
.
Y2
),
precision
))
{
return
(
null
);
return
new
PointF
((
float
)
xi
,
(
float
)
yi
);
}
var
denom
=
a1
*
b2
-
a2
*
b1
;
if
(
denom
==
0
)
else
{
return
null
;
}
var
offset
=
denom
<
0
?
-
denom
/
2
:
denom
/
2
;
var
num
=
b1
*
c2
-
b2
*
c1
;
var
x
=
(
num
<
0
?
num
-
offset
:
num
+
offset
)
/
denom
;
num
=
a2
*
c1
-
a1
*
c2
;
var
y
=
(
num
<
0
?
num
-
offset
:
num
+
offset
)
/
denom
;
return
new
PointF
(
x
,
y
);
}
}
private
static
void
AddIfIntersect
(
LineF
first
,
LineF
second
,
ICollection
<
PointF
>
result
)
...
...
Source/Painting/SvgMarker.cs
View file @
1585c700
...
...
@@ -87,11 +87,11 @@ namespace Svg
Overflow
=
SvgOverflow
.
hidden
;
}
public
override
System
.
Drawing
.
Drawing2D
.
GraphicsPath
Path
(
SvgRenderer
renderer
)
public
override
System
.
Drawing
.
Drawing2D
.
GraphicsPath
Path
(
I
SvgRenderer
renderer
)
{
var
path
=
this
.
Children
.
FirstOrDefault
(
x
=>
x
is
Svg
Path
);
var
path
=
this
.
Children
.
FirstOrDefault
(
x
=>
x
is
Svg
VisualElement
);
if
(
path
!=
null
)
return
(
path
as
Svg
Path
).
Path
(
renderer
);
return
(
path
as
Svg
VisualElement
).
Path
(
renderer
);
return
null
;
}
...
...
@@ -131,7 +131,7 @@ namespace Svg
/// <param name="pOwner"></param>
/// <param name="pMarkerPoint1"></param>
/// <param name="pMarkerPoint2"></param>
public
void
RenderMarker
(
SvgRenderer
pRenderer
,
Svg
Path
pOwner
,
PointF
pRefPoint
,
PointF
pMarkerPoint1
,
PointF
pMarkerPoint2
)
public
void
RenderMarker
(
I
SvgRenderer
pRenderer
,
Svg
VisualElement
pOwner
,
PointF
pRefPoint
,
PointF
pMarkerPoint1
,
PointF
pMarkerPoint2
)
{
float
xDiff
=
pMarkerPoint2
.
X
-
pMarkerPoint1
.
X
;
float
yDiff
=
pMarkerPoint2
.
Y
-
pMarkerPoint1
.
Y
;
...
...
@@ -148,7 +148,7 @@ namespace Svg
/// <param name="pMarkerPoint1"></param>
/// <param name="pMarkerPoint2"></param>
/// <param name="pMarkerPoint3"></param>
public
void
RenderMarker
(
SvgRenderer
pRenderer
,
Svg
Path
pOwner
,
PointF
pRefPoint
,
PointF
pMarkerPoint1
,
PointF
pMarkerPoint2
,
PointF
pMarkerPoint3
)
public
void
RenderMarker
(
I
SvgRenderer
pRenderer
,
Svg
VisualElement
pOwner
,
PointF
pRefPoint
,
PointF
pMarkerPoint1
,
PointF
pMarkerPoint2
,
PointF
pMarkerPoint3
)
{
float
xDiff
=
pMarkerPoint2
.
X
-
pMarkerPoint1
.
X
;
float
yDiff
=
pMarkerPoint2
.
Y
-
pMarkerPoint1
.
Y
;
...
...
@@ -168,13 +168,14 @@ namespace Svg
/// <param name="pRenderer"></param>
/// <param name="pOwner"></param>
/// <param name="pMarkerPoint"></param>
private
void
RenderPart2
(
float
fAngle
,
SvgRenderer
pRenderer
,
SvgPath
pOwner
,
PointF
pMarkerPoint
)
private
void
RenderPart2
(
float
fAngle
,
ISvgRenderer
pRenderer
,
SvgVisualElement
pOwner
,
PointF
pMarkerPoint
)
{
using
(
var
pRenderPen
=
CreatePen
(
pOwner
,
pRenderer
))
{
using
(
var
markerPath
=
GetClone
(
pOwner
))
{
using
(
var
transMatrix
=
new
Matrix
())
{
Pen
pRenderPen
=
CreatePen
(
pOwner
,
pRenderer
);
GraphicsPath
markerPath
=
GetClone
(
pOwner
);
Matrix
transMatrix
=
new
Matrix
();
transMatrix
.
Translate
(
pMarkerPoint
.
X
,
pMarkerPoint
.
Y
);
if
(
Orient
.
IsAuto
)
transMatrix
.
Rotate
(
fAngle
);
...
...
@@ -194,21 +195,22 @@ namespace Svg
break
;
}
markerPath
.
Transform
(
transMatrix
);
pRenderer
.
DrawPath
(
pRenderPen
,
markerPath
);
if
(
pRenderPen
!=
null
)
pRenderer
.
DrawPath
(
pRenderPen
,
markerPath
);
SvgPaintServer
pFill
=
Fill
;
SvgPaintServer
pFill
=
this
.
Children
.
First
().
Fill
;
SvgFillRule
pFillRule
=
FillRule
;
// TODO: What do we use the fill rule for?
float
fOpacity
=
FillOpacity
;
if
(
pFill
!=
null
)
{
Brush
pBrush
=
pFill
.
GetBrush
(
this
,
pRenderer
,
fOpacity
);
using
(
var
pBrush
=
pFill
.
GetBrush
(
this
,
pRenderer
,
fOpacity
))
{
pRenderer
.
FillPath
(
pBrush
,
markerPath
);
pBrush
.
Dispose
();
}
pRenderPen
.
Dispose
();
markerPath
.
Dispose
();
transMatrix
.
Dispose
();
}
}
}
}
}
/// <summary>
...
...
@@ -216,8 +218,9 @@ namespace Svg
/// </summary>
/// <param name="pStroke"></param>
/// <returns></returns>
private
Pen
CreatePen
(
Svg
Path
pPath
,
SvgRenderer
renderer
)
private
Pen
CreatePen
(
Svg
VisualElement
pPath
,
I
SvgRenderer
renderer
)
{
if
(
pPath
.
Stroke
==
null
)
return
null
;
Brush
pBrush
=
pPath
.
Stroke
.
GetBrush
(
this
,
renderer
,
Opacity
);
switch
(
MarkerUnits
)
{
...
...
@@ -231,18 +234,20 @@ namespace Svg
}
/// <summary>
/// Get a clone of the current path, scaled for the stroke with
/// Get a clone of the current path, scaled for the stroke wi
d
th
/// </summary>
/// <returns></returns>
private
GraphicsPath
GetClone
(
Svg
Path
pPath
)
private
GraphicsPath
GetClone
(
Svg
VisualElement
pPath
)
{
GraphicsPath
pRet
=
Path
(
null
).
Clone
()
as
GraphicsPath
;
switch
(
MarkerUnits
)
{
case
SvgMarkerUnits
.
strokeWidth
:
Matrix
transMatrix
=
new
Matrix
();
using
(
var
transMatrix
=
new
Matrix
())
{
transMatrix
.
Scale
(
AdjustForViewBoxWidth
(
pPath
.
StrokeWidth
),
AdjustForViewBoxHeight
(
pPath
.
StrokeWidth
));
pRet
.
Transform
(
transMatrix
);
}
break
;
case
SvgMarkerUnits
.
userSpaceOnUse
:
break
;
...
...
@@ -258,7 +263,7 @@ namespace Svg
private
float
AdjustForViewBoxWidth
(
float
fWidth
)
{
// TODO: We know this isn't correct
return
(
fWidth
/
ViewBox
.
Width
);
return
(
ViewBox
.
Width
<=
0
?
1
:
fWidth
/
ViewBox
.
Width
);
}
/// <summary>
...
...
@@ -269,7 +274,7 @@ namespace Svg
private
float
AdjustForViewBoxHeight
(
float
fHeight
)
{
// TODO: We know this isn't correct
return
(
fHeight
/
ViewBox
.
Height
);
return
(
ViewBox
.
Height
<=
0
?
1
:
fHeight
/
ViewBox
.
Height
);
}
}
}
\ No newline at end of file
Source/Painting/SvgPaintServer.cs
View file @
1585c700
...
...
@@ -13,6 +13,8 @@ namespace Svg
[
TypeConverter
(
typeof
(
SvgPaintServerFactory
))]
public
abstract
class
SvgPaintServer
:
SvgElement
{
public
Func
<
SvgPaintServer
>
GetCallback
{
get
;
set
;
}
/// <summary>
/// An unspecified <see cref="SvgPaintServer"/>.
/// </summary>
...
...
@@ -26,10 +28,10 @@ namespace Svg
}
/// <summary>
/// Renders the <see cref="SvgElement"/> and contents to the specified <see cref="SvgRenderer"/> object.
/// Renders the <see cref="SvgElement"/> and contents to the specified <see cref="
I
SvgRenderer"/> object.
/// </summary>
/// <param name="renderer">The <see cref="SvgRenderer"/> object to render to.</param>
protected
override
void
Render
(
SvgRenderer
renderer
)
/// <param name="renderer">The <see cref="
I
SvgRenderer"/> object to render to.</param>
protected
override
void
Render
(
I
SvgRenderer
renderer
)
{
// Never render paint servers or their children
}
...
...
@@ -39,7 +41,7 @@ namespace Svg
/// </summary>
/// <param name="styleOwner">The owner <see cref="SvgVisualElement"/>.</param>
/// <param name="opacity">The opacity of the brush.</param>
public
abstract
Brush
GetBrush
(
SvgVisualElement
styleOwner
,
SvgRenderer
renderer
,
float
opacity
);
public
abstract
Brush
GetBrush
(
SvgVisualElement
styleOwner
,
I
SvgRenderer
renderer
,
float
opacity
,
bool
forStroke
=
false
);
/// <summary>
/// Returns a <see cref="T:System.String"/> that represents the current <see cref="T:System.Object"/>.
...
...
Source/Painting/SvgPaintServerFactory.cs
View file @
1585c700
using
System
;
using
System.ComponentModel
;
using
System.Collections.Generic
;
using
System.Text
;
using
System.Text.RegularExpressions
;
using
System.Xml
;
using
System.ComponentModel
;
using
System.Drawing
;
using
System.Globalization
;
using
System.Linq
;
namespace
Svg
{
internal
class
SvgPaintServerFactory
:
TypeConverter
{
private
static
readonly
SvgColourConverter
_colourConverter
;
private
static
readonly
Regex
_urlRefPattern
;
static
SvgPaintServerFactory
()
{
_colourConverter
=
new
SvgColourConverter
();
_urlRefPattern
=
new
Regex
(
@"url\((#[^)]+)\)"
);
}
public
static
SvgPaintServer
Create
(
string
value
,
SvgDocument
document
)
...
...
@@ -35,11 +31,18 @@ namespace Svg
{
return
new
SvgDeferredPaintServer
(
document
,
value
);
}
else
if
(
value
.
IndexOf
(
"url(#"
)
>
-
1
)
else
{
var
servers
=
new
List
<
SvgPaintServer
>();
while
(!
string
.
IsNullOrEmpty
(
value
))
{
Match
match
=
_urlRefPattern
.
Match
(
value
);
Uri
id
=
new
Uri
(
match
.
Groups
[
1
].
Value
,
UriKind
.
Relative
);
return
(
SvgPaintServer
)
document
.
IdManager
.
GetElementById
(
id
);
if
(
value
.
StartsWith
(
"url(#"
))
{
var
leftParen
=
value
.
IndexOf
(
')'
,
5
);
Uri
id
=
new
Uri
(
value
.
Substring
(
5
,
leftParen
-
5
),
UriKind
.
Relative
);
value
=
value
.
Substring
(
leftParen
+
1
).
Trim
();
servers
.
Add
((
SvgPaintServer
)
document
.
IdManager
.
GetElementById
(
id
));
}
// If referenced to to a different (linear or radial) gradient
else
if
(
document
.
IdManager
.
GetElementById
(
value
)
!=
null
&&
document
.
IdManager
.
GetElementById
(
value
).
GetType
().
BaseType
==
typeof
(
SvgGradientServer
))
...
...
@@ -48,19 +51,49 @@ namespace Svg
}
else
if
(
value
.
StartsWith
(
"#"
))
// Otherwise try and parse as colour
{
try
switch
(
CountHexDigits
(
value
,
1
))
{
case
3
:
servers
.
Add
(
new
SvgColourServer
((
Color
)
_colourConverter
.
ConvertFrom
(
value
.
Substring
(
0
,
4
))));
value
=
value
.
Substring
(
4
).
Trim
();
break
;
case
6
:
servers
.
Add
(
new
SvgColourServer
((
Color
)
_colourConverter
.
ConvertFrom
(
value
.
Substring
(
0
,
7
))));
value
=
value
.
Substring
(
7
).
Trim
();
break
;
default
:
return
new
SvgDeferredPaintServer
(
document
,
value
);
}
}
else
{
return
new
SvgColourServer
((
Color
)
_colourConverter
.
ConvertFrom
(
value
.
Trim
()));
}
catch
}
if
(
servers
.
Count
>
1
)
{
return
new
Svg
Deferred
PaintServer
(
document
,
value
);
return
new
Svg
Fallback
PaintServer
(
servers
[
0
],
servers
.
Skip
(
1
)
);
}
return
servers
[
0
];
}
else
}
private
static
int
CountHexDigits
(
string
value
,
int
start
)
{
return
new
SvgColourServer
((
Color
)
_colourConverter
.
ConvertFrom
(
value
.
Trim
()));
int
i
=
Math
.
Max
(
start
,
0
);
int
count
=
0
;
while
(
i
<
value
.
Length
&&
((
value
[
i
]
>=
'0'
&&
value
[
i
]
<=
'9'
)
||
(
value
[
i
]
>=
'a'
&&
value
[
i
]
<=
'f'
)
||
(
value
[
i
]
>=
'A'
&&
value
[
i
]
<=
'F'
)))
{
count
++;
i
++;
}
return
count
;
}
public
override
object
ConvertFrom
(
ITypeDescriptorContext
context
,
System
.
Globalization
.
CultureInfo
culture
,
object
value
)
...
...
Source/Painting/SvgPatternServer.cs
View file @
1585c700
...
...
@@ -6,6 +6,7 @@ using System.Drawing;
using
System.ComponentModel
;
using
Svg.Transforms
;
using
System.Linq
;
namespace
Svg
{
...
...
@@ -19,9 +20,10 @@ namespace Svg
private
SvgUnit
_height
;
private
SvgUnit
_x
;
private
SvgUnit
_y
;
private
SvgPaintServer
_inheritGradient
;
private
SvgViewBox
_viewBox
;
private
SvgCoordinateUnits
_patternUnits
;
private
SvgCoordinateUnits
_patternContentUnits
;
private
SvgCoordinateUnits
_patternUnits
=
SvgCoordinateUnits
.
Inherit
;
private
SvgCoordinateUnits
_patternContentUnits
=
SvgCoordinateUnits
.
Inherit
;
[
SvgAttribute
(
"overflow"
)]
public
SvgOverflow
Overflow
...
...
@@ -76,7 +78,7 @@ namespace Svg
/// <summary>
/// Gets or sets the width of the pattern.
/// </summary>
[
SvgAttribute
(
"patternUnits"
)]
[
SvgAttribute
(
"pattern
Content
Units"
)]
public
SvgCoordinateUnits
PatternContentUnits
{
get
{
return
this
.
_patternContentUnits
;
}
...
...
@@ -113,15 +115,56 @@ namespace Svg
set
{
this
.
_y
=
value
;
}
}
/// <summary>
/// Gets or sets another gradient fill from which to inherit the stops from.
/// </summary>
[
SvgAttribute
(
"href"
,
SvgAttributeAttribute
.
XLinkNamespace
)]
public
SvgPaintServer
InheritGradient
{
get
{
return
this
.
_inheritGradient
;
}
set
{
this
.
_inheritGradient
=
value
;
}
}
[
SvgAttribute
(
"patternTransform"
)]
public
SvgTransformCollection
PatternTransform
{
get
{
return
(
this
.
Attributes
.
GetAttribute
<
SvgTransformCollection
>(
"gradientTransform"
));
}
set
{
this
.
Attributes
[
"gradientTransform"
]
=
value
;
}
}
protected
Matrix
EffectivePatternTransform
{
get
{
var
transform
=
new
Matrix
();
if
(
PatternTransform
!=
null
)
{
transform
.
Multiply
(
PatternTransform
.
GetMatrix
());
}
return
transform
;
}
}
/// <summary>
/// Initializes a new instance of the <see cref="SvgPatternServer"/> class.
/// </summary>
public
SvgPatternServer
()
{
this
.
_x
=
new
SvgUnit
(
0.0f
);
this
.
_y
=
new
SvgUnit
(
0.0f
);
this
.
_width
=
new
SvgUnit
(
0.0f
);
this
.
_height
=
new
SvgUnit
(
0.0f
);
this
.
_x
=
SvgUnit
.
None
;
this
.
_y
=
SvgUnit
.
None
;
this
.
_width
=
SvgUnit
.
None
;
this
.
_height
=
SvgUnit
.
None
;
}
private
SvgUnit
NormalizeUnit
(
SvgUnit
orig
)
{
return
(
orig
.
Type
==
SvgUnitType
.
Percentage
&&
this
.
PatternUnits
==
SvgCoordinateUnits
.
ObjectBoundingBox
?
new
SvgUnit
(
SvgUnitType
.
User
,
orig
.
Value
/
100
)
:
orig
);
}
/// <summary>
...
...
@@ -129,76 +172,85 @@ namespace Svg
/// </summary>
/// <param name="renderingElement">The owner <see cref="SvgVisualElement"/>.</param>
/// <param name="opacity">The opacity of the brush.</param>
public
override
Brush
GetBrush
(
SvgVisualElement
renderingElement
,
SvgRenderer
renderer
,
float
opacity
)
public
override
Brush
GetBrush
(
SvgVisualElement
renderingElement
,
ISvgRenderer
renderer
,
float
opacity
,
bool
forStroke
=
false
)
{
var
chain
=
new
List
<
SvgPatternServer
>();
var
curr
=
this
;
while
(
curr
!=
null
)
{
// If there aren't any children, return null
if
(
this
.
Children
.
Count
==
0
)
return
null
;
chain
.
Add
(
curr
);
curr
=
SvgDeferredPaintServer
.
TryGet
<
SvgPatternServer
>(
curr
.
_inheritGradient
,
renderingElement
);
}
// Can't render if there are no dimensions
if
(
this
.
_width
.
Value
==
0.0f
||
this
.
_height
.
Value
==
0.0f
)
return
null
;
var
childElem
=
chain
.
Where
((
p
)
=>
p
.
Children
!=
null
&&
p
.
Children
.
Count
>
0
).
FirstOrDefault
();
if
(
childElem
==
null
)
return
null
;
var
widthElem
=
chain
.
Where
((
p
)
=>
p
.
Width
!=
null
&&
p
.
Width
!=
SvgUnit
.
None
).
FirstOrDefault
();
var
heightElem
=
chain
.
Where
((
p
)
=>
p
.
Height
!=
null
&&
p
.
Height
!=
SvgUnit
.
None
).
FirstOrDefault
();
if
(
widthElem
==
null
&&
heightElem
==
null
)
return
null
;
try
{
if
(
this
.
PatternUnits
==
SvgCoordinateUnits
.
ObjectBoundingBox
)
renderer
.
Boundable
(
renderingElement
);
var
viewBoxElem
=
chain
.
Where
((
p
)
=>
p
.
ViewBox
!=
null
&&
p
.
ViewBox
!=
SvgViewBox
.
Empty
).
FirstOrDefault
();
var
viewBox
=
viewBoxElem
==
null
?
SvgViewBox
.
Empty
:
viewBoxElem
.
ViewBox
;
var
xElem
=
chain
.
Where
((
p
)
=>
p
.
X
!=
null
&&
p
.
X
!=
SvgUnit
.
None
).
FirstOrDefault
();
var
yElem
=
chain
.
Where
((
p
)
=>
p
.
Y
!=
null
&&
p
.
Y
!=
SvgUnit
.
None
).
FirstOrDefault
();
var
xUnit
=
xElem
==
null
?
SvgUnit
.
Empty
:
xElem
.
X
;
var
yUnit
=
yElem
==
null
?
SvgUnit
.
Empty
:
yElem
.
Y
;
float
width
=
this
.
_width
.
ToDeviceValue
(
renderer
,
UnitRenderingType
.
Horizontal
,
this
);
float
height
=
this
.
_height
.
ToDeviceValue
(
renderer
,
UnitRenderingType
.
Vertical
,
this
);
var
patternUnitElem
=
chain
.
Where
((
p
)
=>
p
.
PatternUnits
!=
SvgCoordinateUnits
.
Inherit
).
FirstOrDefault
();
var
patternUnits
=
(
patternUnitElem
==
null
?
SvgCoordinateUnits
.
ObjectBoundingBox
:
patternUnitElem
.
PatternUnits
);
var
patternContentUnitElem
=
chain
.
Where
((
p
)
=>
p
.
PatternContentUnits
!=
SvgCoordinateUnits
.
Inherit
).
FirstOrDefault
();
var
patternContentUnits
=
(
patternContentUnitElem
==
null
?
SvgCoordinateUnits
.
UserSpaceOnUse
:
patternContentUnitElem
.
PatternContentUnits
);
Matrix
patternMatrix
=
new
Matrix
();
// Apply a translate if needed
if
(
this
.
_x
.
Value
>
0.0f
||
this
.
_y
.
Value
>
0.0f
)
try
{
float
x
=
this
.
_x
.
ToDeviceValue
(
renderer
,
UnitRenderingType
.
HorizontalOffset
,
this
);
float
y
=
this
.
_y
.
ToDeviceValue
(
renderer
,
UnitRenderingType
.
VerticalOffset
,
this
);
if
(
patternUnits
==
SvgCoordinateUnits
.
ObjectBoundingBox
)
renderer
.
SetBoundable
(
renderingElement
);
patternMatrix
.
Translate
(
x
+
-
1.0f
,
y
+
-
1.0f
);
}
else
using
(
var
patternMatrix
=
new
Matrix
())
{
patternMatrix
.
Translate
(-
1
,
-
1
);
}
var
bounds
=
renderer
.
GetBoundable
().
Bounds
;
var
xScale
=
(
patternUnits
==
SvgCoordinateUnits
.
ObjectBoundingBox
?
bounds
.
Width
:
1
);
var
yScale
=
(
patternUnits
==
SvgCoordinateUnits
.
ObjectBoundingBox
?
bounds
.
Height
:
1
);
if
(
this
.
ViewBox
.
Height
>
0
||
this
.
ViewBox
.
Width
>
0
)
{
patternMatrix
.
Scale
(
this
.
Width
.
ToDeviceValue
(
renderer
,
UnitRenderingType
.
Horizontal
,
this
)
/
this
.
ViewBox
.
Width
,
this
.
Height
.
ToDeviceValue
(
renderer
,
UnitRenderingType
.
Vertical
,
this
)
/
this
.
ViewBox
.
Height
);
}
float
x
=
xScale
*
NormalizeUnit
(
xUnit
).
ToDeviceValue
(
renderer
,
UnitRenderingType
.
Horizontal
,
this
);
float
y
=
yScale
*
NormalizeUnit
(
yUnit
).
ToDeviceValue
(
renderer
,
UnitRenderingType
.
Vertical
,
this
);
float
width
=
xScale
*
NormalizeUnit
(
widthElem
.
Width
).
ToDeviceValue
(
renderer
,
UnitRenderingType
.
Horizontal
,
this
);
float
height
=
yScale
*
NormalizeUnit
(
heightElem
.
Height
).
ToDeviceValue
(
renderer
,
UnitRenderingType
.
Vertical
,
this
);
// Apply a scale if needed
patternMatrix
.
Scale
((
patternContentUnits
==
SvgCoordinateUnits
.
ObjectBoundingBox
?
bounds
.
Width
:
1
)
*
(
viewBox
.
Width
>
0
?
width
/
viewBox
.
Width
:
1
),
(
patternContentUnits
==
SvgCoordinateUnits
.
ObjectBoundingBox
?
bounds
.
Height
:
1
)
*
(
viewBox
.
Height
>
0
?
height
/
viewBox
.
Height
:
1
),
MatrixOrder
.
Prepend
);
Bitmap
image
=
new
Bitmap
((
int
)
width
,
(
int
)
height
);
using
(
SvgRendere
r
iRenderer
=
SvgRenderer
.
FromImage
(
image
))
using
(
va
r
iRenderer
=
SvgRenderer
.
FromImage
(
image
))
{
iRenderer
.
Boundable
((
_patternContentUnits
==
SvgCoordinateUnits
.
ObjectBoundingBox
)
?
new
GenericBoundable
(
0
,
0
,
width
,
height
)
:
renderer
.
Boundable
());
iRenderer
.
Set
Boundable
((
_patternContentUnits
==
SvgCoordinateUnits
.
ObjectBoundingBox
)
?
new
GenericBoundable
(
0
,
0
,
width
,
height
)
:
renderer
.
Get
Boundable
());
iRenderer
.
Transform
=
patternMatrix
;
iRenderer
.
CompositingQuality
=
CompositingQuality
.
HighQuality
;
iRenderer
.
SmoothingMode
=
SmoothingMode
.
AntiAlias
;
iRenderer
.
PixelOffsetMode
=
PixelOffsetMode
.
Half
;
iRenderer
.
SetClip
(
new
Region
(
new
RectangleF
(
0
,
0
,
viewBox
.
Width
>
0
?
viewBox
.
Width
:
width
,
viewBox
.
Height
>
0
?
viewBox
.
Height
:
height
)));
foreach
(
SvgElement
child
in
t
hi
s
.
Children
)
foreach
(
SvgElement
child
in
c
hi
ldElem
.
Children
)
{
child
.
RenderElement
(
iRenderer
);
}
iRenderer
.
Save
();
}
image
.
Save
(
string
.
Format
(
@"C:\test{0:D3}.png"
,
imgNumber
++));
TextureBrush
textureBrush
=
new
TextureBrush
(
image
);
var
brushTransform
=
EffectivePatternTransform
.
Clone
();
brushTransform
.
Translate
(
x
,
y
,
MatrixOrder
.
Append
);
textureBrush
.
Transform
=
brushTransform
;
return
textureBrush
;
}
}
finally
{
if
(
this
.
PatternUnits
==
SvgCoordinateUnits
.
ObjectBoundingBox
)
renderer
.
PopBoundable
();
}
}
private
static
int
imgNumber
=
0
;
public
override
SvgElement
DeepCopy
()
{
return
DeepCopy
<
SvgPatternServer
>();
...
...
Source/Painting/SvgRadialGradientServer.cs
View file @
1585c700
using
System
;
using
System.Diagnostics
;
using
System.Drawing
;
using
System.Collections.Generic
;
using
System.Drawing.Drawing2D
;
using
System.Linq
;
...
...
@@ -95,88 +96,207 @@ namespace Svg
Radius
=
new
SvgUnit
(
SvgUnitType
.
Percentage
,
50F
);
}
public
override
Brush
GetBrush
(
SvgVisualElement
renderingElement
,
SvgRenderer
renderer
,
float
opacity
)
private
object
_lockObj
=
new
Object
();
private
SvgUnit
NormalizeUnit
(
SvgUnit
orig
)
{
return
(
orig
.
Type
==
SvgUnitType
.
Percentage
&&
this
.
GradientUnits
==
SvgCoordinateUnits
.
ObjectBoundingBox
?
new
SvgUnit
(
SvgUnitType
.
User
,
orig
.
Value
/
100
)
:
orig
);
}
public
override
Brush
GetBrush
(
SvgVisualElement
renderingElement
,
ISvgRenderer
renderer
,
float
opacity
,
bool
forStroke
=
false
)
{
LoadStops
(
renderingElement
);
try
{
if
(
this
.
GradientUnits
==
SvgCoordinateUnits
.
ObjectBoundingBox
)
renderer
.
Boundable
(
renderingElement
);
var
origin
=
renderer
.
Boundable
().
Location
;
var
centerPoint
=
CalculateCenterPoint
(
renderer
,
origin
);
var
focalPoint
=
CalculateFocalPoint
(
renderer
,
origin
);
if
(
this
.
GradientUnits
==
SvgCoordinateUnits
.
ObjectBoundingBox
)
renderer
.
SetBoundable
(
renderingElement
);
var
specifiedRadius
=
CalculateRadius
(
renderer
);
var
effectiveRadius
=
CalculateEffectiveRadius
(
renderingElement
,
centerPoint
,
specifiedRadius
);
// Calculate the path and transform it appropriately
var
center
=
new
PointF
(
NormalizeUnit
(
CenterX
).
ToDeviceValue
(
renderer
,
UnitRenderingType
.
Horizontal
,
this
),
NormalizeUnit
(
CenterY
).
ToDeviceValue
(
renderer
,
UnitRenderingType
.
Vertical
,
this
));
var
focals
=
new
PointF
[]
{
new
PointF
(
NormalizeUnit
(
FocalX
).
ToDeviceValue
(
renderer
,
UnitRenderingType
.
Horizontal
,
this
),
NormalizeUnit
(
FocalY
).
ToDeviceValue
(
renderer
,
UnitRenderingType
.
Vertical
,
this
))
};
var
specifiedRadius
=
NormalizeUnit
(
Radius
).
ToDeviceValue
(
renderer
,
UnitRenderingType
.
Other
,
this
);
var
path
=
new
GraphicsPath
();
path
.
AddEllipse
(
center
.
X
-
specifiedRadius
,
center
.
Y
-
specifiedRadius
,
specifiedRadius
*
2
,
specifiedRadius
*
2
);
var
brush
=
new
PathGradientBrush
(
CreateGraphicsPath
(
origin
,
centerPoint
,
e
ffective
R
adi
us
)
)
using
(
var
transform
=
E
ffective
Gr
adi
entTransform
)
{
InterpolationColors
=
CalculateColorBlend
(
renderer
,
opacity
,
specifiedRadius
,
effectiveRadius
),
CenterPoint
=
focalPoint
};
var
bounds
=
renderer
.
GetBoundable
().
Bounds
;
transform
.
Translate
(
bounds
.
X
,
bounds
.
Y
,
MatrixOrder
.
Prepend
);
if
(
this
.
GradientUnits
==
SvgCoordinateUnits
.
ObjectBoundingBox
)
{
transform
.
Scale
(
bounds
.
Width
,
bounds
.
Height
,
MatrixOrder
.
Prepend
);
}
path
.
Transform
(
transform
);
transform
.
TransformPoints
(
focals
);
}
Debug
.
Assert
(
brush
.
Rectangle
.
Contains
(
renderingElement
.
Bounds
),
"Brush rectangle does not contain rendering element bounds!"
);
return
brush
;
// Calculate any required scaling
var
scaleBounds
=
RectangleF
.
Inflate
(
renderingElement
.
Bounds
,
renderingElement
.
StrokeWidth
,
renderingElement
.
StrokeWidth
);
var
scale
=
CalcScale
(
scaleBounds
,
path
);
// Not ideal, but this makes sure that the rest of the shape gets properly filled or drawn
if
(
scale
>
1.0f
&&
SpreadMethod
==
SvgGradientSpreadMethod
.
Pad
)
{
var
stop
=
Stops
.
Last
();
var
origColor
=
stop
.
GetColor
(
renderingElement
);
var
renderColor
=
System
.
Drawing
.
Color
.
FromArgb
((
int
)(
opacity
*
stop
.
GetOpacity
()
*
255
),
origColor
);
var
origClip
=
renderer
.
GetClip
();
try
{
using
(
var
solidBrush
=
new
SolidBrush
(
renderColor
))
{
var
newClip
=
origClip
.
Clone
();
newClip
.
Exclude
(
path
);
renderer
.
SetClip
(
newClip
);
var
renderPath
=
(
GraphicsPath
)
renderingElement
.
Path
(
renderer
);
if
(
forStroke
)
{
using
(
var
pen
=
new
Pen
(
solidBrush
,
renderingElement
.
StrokeWidth
.
ToDeviceValue
(
renderer
,
UnitRenderingType
.
Other
,
renderingElement
)))
{
renderer
.
DrawPath
(
pen
,
renderPath
);
}
}
else
{
renderer
.
FillPath
(
solidBrush
,
renderPath
);
}
}
}
finally
{
if
(
this
.
GradientUnits
==
SvgCoordinateUnits
.
ObjectBoundingBox
)
renderer
.
PopBoundable
(
);
renderer
.
SetClip
(
origClip
);
}
}
private
PointF
CalculateCenterPoint
(
SvgRenderer
renderer
,
PointF
origin
)
// Get the color blend and any tweak to the scaling
var
blend
=
CalculateColorBlend
(
renderer
,
opacity
,
scale
,
out
scale
);
// Transform the path based on the scaling
var
gradBounds
=
path
.
GetBounds
();
var
transCenter
=
new
PointF
(
gradBounds
.
Left
+
gradBounds
.
Width
/
2
,
gradBounds
.
Top
+
gradBounds
.
Height
/
2
);
using
(
var
scaleMat
=
new
Matrix
())
{
var
deviceCenterX
=
origin
.
X
+
CenterX
.
ToDeviceValue
(
renderer
,
UnitRenderingType
.
HorizontalOffset
,
this
);
var
deviceCenterY
=
origin
.
Y
+
CenterY
.
ToDeviceV
al
u
e
(
renderer
,
UnitRenderingType
.
VerticalOffset
,
this
);
var
transformedCenterPoint
=
TransformPoint
(
new
PointF
(
deviceCenterX
,
deviceCenterY
)
);
return
transformedCenterPoint
;
scaleMat
.
Translate
(-
1
*
transCenter
.
X
,
-
1
*
transCenter
.
Y
,
MatrixOrder
.
Append
);
scaleMat
.
Sc
ale
(
scale
,
scale
,
MatrixOrder
.
Append
);
scaleMat
.
Translate
(
transCenter
.
X
,
transCenter
.
Y
,
MatrixOrder
.
Append
);
path
.
Transform
(
scaleMat
)
;
}
private
PointF
CalculateFocalPoint
(
SvgRenderer
renderer
,
PointF
origin
)
// calculate the brush
var
brush
=
new
PathGradientBrush
(
path
);
brush
.
CenterPoint
=
focals
[
0
];
brush
.
InterpolationColors
=
blend
;
return
brush
;
}
finally
{
var
deviceFocalX
=
origin
.
X
+
FocalX
.
ToDeviceValue
(
renderer
,
UnitRenderingType
.
HorizontalOffset
,
this
);
var
deviceFocalY
=
origin
.
Y
+
FocalY
.
ToDeviceValue
(
renderer
,
UnitRenderingType
.
VerticalOffset
,
this
);
var
transformedFocalPoint
=
TransformPoint
(
new
PointF
(
deviceFocalX
,
deviceFocalY
));
return
transformedFocalPoint
;
if
(
this
.
GradientUnits
==
SvgCoordinateUnits
.
ObjectBoundingBox
)
renderer
.
PopBoundable
();
}
}
private
float
CalculateRadius
(
SvgRenderer
renderer
)
/// <summary>
/// Determine how much (approximately) the path must be scaled to contain the rectangle
/// </summary>
/// <param name="bounds">Bounds that the path must contain</param>
/// <param name="path">Path of the gradient</param>
/// <returns>Scale factor</returns>
/// <remarks>
/// This method continually transforms the rectangle (fewer points) until it is contained by the path
/// and returns the result of the search. The scale factor is set to a constant 95%
/// </remarks>
private
float
CalcScale
(
RectangleF
bounds
,
GraphicsPath
path
)
{
var
points
=
new
PointF
[]
{
new
PointF
(
bounds
.
Left
,
bounds
.
Top
),
new
PointF
(
bounds
.
Right
,
bounds
.
Top
),
new
PointF
(
bounds
.
Right
,
bounds
.
Bottom
),
new
PointF
(
bounds
.
Left
,
bounds
.
Bottom
)
};
var
pathBounds
=
path
.
GetBounds
();
var
pathCenter
=
new
PointF
(
pathBounds
.
X
+
pathBounds
.
Width
/
2
,
pathBounds
.
Y
+
pathBounds
.
Height
/
2
);
using
(
var
transform
=
new
Matrix
())
{
transform
.
Translate
(-
1
*
pathCenter
.
X
,
-
1
*
pathCenter
.
Y
,
MatrixOrder
.
Append
);
transform
.
Scale
(.
95f
,
.
95f
,
MatrixOrder
.
Append
);
transform
.
Translate
(
pathCenter
.
X
,
pathCenter
.
Y
,
MatrixOrder
.
Append
);
var
boundsTest
=
RectangleF
.
Inflate
(
bounds
,
0
,
0
);
while
(!(
path
.
IsVisible
(
points
[
0
])
&&
path
.
IsVisible
(
points
[
1
])
&&
path
.
IsVisible
(
points
[
2
])
&&
path
.
IsVisible
(
points
[
3
])))
{
var
radius
=
Radius
.
ToDeviceValue
(
renderer
,
UnitRenderingType
.
Other
,
this
);
var
transformRadiusVector
=
TransformVector
(
new
PointF
(
radius
,
0
));
var
transformedRadius
=
CalculateLength
(
transformRadiusVector
);
return
transformedRadius
;
transform
.
TransformPoints
(
points
);
}
}
return
bounds
.
Height
/
(
points
[
2
].
Y
-
points
[
1
].
Y
);
}
//New plan:
// scale the outer rectangle to always encompass ellipse
// cut the ellipse in half (either vertical or horizontal)
// determine the region on each side of the ellipse
private
static
IEnumerable
<
GraphicsPath
>
GetDifference
(
RectangleF
subject
,
GraphicsPath
clip
)
{
var
clipFlat
=
(
GraphicsPath
)
clip
.
Clone
();
clipFlat
.
Flatten
();
var
clipBounds
=
clipFlat
.
GetBounds
();
var
bounds
=
RectangleF
.
Union
(
subject
,
clipBounds
);
bounds
.
Inflate
(
bounds
.
Width
*
.
3f
,
bounds
.
Height
*
0.3f
);
private
float
CalculateEffectiveRadius
(
ISvgBoundable
boundable
,
PointF
centerPoint
,
float
specifiedRadius
)
var
clipMidPoint
=
new
PointF
((
clipBounds
.
Left
+
clipBounds
.
Right
)
/
2
,
(
clipBounds
.
Top
+
clipBounds
.
Bottom
)
/
2
);
var
leftPoints
=
new
List
<
PointF
>();
var
rightPoints
=
new
List
<
PointF
>();
foreach
(
var
pt
in
clipFlat
.
PathPoints
)
{
if
(
pt
.
X
<=
clipMidPoint
.
X
)
{
if
(
SpreadMethod
!=
SvgGradientSpreadMethod
.
Pad
)
leftPoints
.
Add
(
pt
);
}
else
{
return
specifiedRadius
;
rightPoints
.
Add
(
pt
);
}
}
leftPoints
.
Sort
((
p
,
q
)
=>
p
.
Y
.
CompareTo
(
q
.
Y
));
rightPoints
.
Sort
((
p
,
q
)
=>
p
.
Y
.
CompareTo
(
q
.
Y
));
var
topLeft
=
new
PointF
(
boundable
.
Bounds
.
Left
,
boundable
.
Bounds
.
Top
);
var
topRight
=
new
PointF
(
boundable
.
Bounds
.
Right
,
boundable
.
Bounds
.
Top
);
var
bottomRight
=
new
PointF
(
boundable
.
Bounds
.
Right
,
boundable
.
Bounds
.
Bottom
);
var
bottomLeft
=
new
PointF
(
boundable
.
Bounds
.
Left
,
boundable
.
Bounds
.
Bottom
);
var
point
=
new
PointF
((
leftPoints
.
Last
().
X
+
rightPoints
.
Last
().
X
)
/
2
,
(
leftPoints
.
Last
().
Y
+
rightPoints
.
Last
().
Y
)
/
2
);
leftPoints
.
Add
(
point
);
rightPoints
.
Add
(
point
);
point
=
new
PointF
(
point
.
X
,
bounds
.
Bottom
);
leftPoints
.
Add
(
point
);
rightPoints
.
Add
(
point
);
var
effectiveRadius
=
(
float
)
Math
.
Ceiling
(
Math
.
Max
(
Math
.
Max
(
CalculateDistance
(
centerPoint
,
topLeft
),
CalculateDistance
(
centerPoint
,
topRight
)
),
Math
.
Max
(
CalculateDistance
(
centerPoint
,
bottomRight
),
CalculateDistance
(
centerPoint
,
bottomLeft
)
)
)
);
leftPoints
.
Add
(
new
PointF
(
bounds
.
Left
,
bounds
.
Bottom
));
leftPoints
.
Add
(
new
PointF
(
bounds
.
Left
,
bounds
.
Top
));
rightPoints
.
Add
(
new
PointF
(
bounds
.
Right
,
bounds
.
Bottom
));
rightPoints
.
Add
(
new
PointF
(
bounds
.
Right
,
bounds
.
Top
));
point
=
new
PointF
((
leftPoints
.
First
().
X
+
rightPoints
.
First
().
X
)
/
2
,
bounds
.
Top
);
leftPoints
.
Add
(
point
);
rightPoints
.
Add
(
point
);
point
=
new
PointF
(
point
.
X
,
(
leftPoints
.
First
().
Y
+
rightPoints
.
First
().
Y
)
/
2
);
leftPoints
.
Add
(
point
);
rightPoints
.
Add
(
point
);
effectiveRadius
=
Math
.
Max
(
effectiveRadius
,
specifiedRadius
);
var
path
=
new
GraphicsPath
(
FillMode
.
Winding
);
path
.
AddPolygon
(
leftPoints
.
ToArray
());
yield
return
path
;
return
effectiveRadius
;
path
.
Reset
();
path
.
AddPolygon
(
rightPoints
.
ToArray
());
yield
return
path
;
}
private
static
GraphicsPath
CreateGraphicsPath
(
PointF
origin
,
PointF
centerPoint
,
float
effectiveRadius
)
...
...
@@ -193,22 +313,75 @@ namespace Svg
return
path
;
}
private
ColorBlend
CalculateColorBlend
(
SvgRenderer
renderer
,
float
opacity
,
float
s
pecifiedRadius
,
float
effectiveRadius
)
private
ColorBlend
CalculateColorBlend
(
I
SvgRenderer
renderer
,
float
opacity
,
float
s
cale
,
out
float
outScale
)
{
var
colorBlend
=
GetColorBlend
(
renderer
,
opacity
,
true
);
float
newScale
;
List
<
float
>
pos
;
List
<
Color
>
colors
;
if
(
specifiedRadius
>=
effectiveRadius
)
outScale
=
scale
;
if
(
scale
>
1
)
{
return
colorBlend
;
switch
(
this
.
SpreadMethod
)
{
case
SvgGradientSpreadMethod
.
Reflect
:
newScale
=
(
float
)
Math
.
Ceiling
(
scale
);
pos
=
(
from
p
in
colorBlend
.
Positions
select
1
+
(
p
-
1
)
/
newScale
).
ToList
();
colors
=
colorBlend
.
Colors
.
ToList
();
for
(
var
i
=
1
;
i
<
newScale
;
i
++)
{
if
(
i
%
2
==
1
)
{
for
(
int
j
=
1
;
j
<
colorBlend
.
Positions
.
Length
;
j
++)
{
pos
.
Insert
(
0
,
(
newScale
-
i
-
1
)
/
newScale
+
1
-
colorBlend
.
Positions
[
j
]);
colors
.
Insert
(
0
,
colorBlend
.
Colors
[
j
]);
}
}
else
{
for
(
int
j
=
0
;
j
<
colorBlend
.
Positions
.
Length
-
1
;
j
++)
{
pos
.
Insert
(
j
,
(
newScale
-
i
-
1
)
/
newScale
+
colorBlend
.
Positions
[
j
]);
colors
.
Insert
(
j
,
colorBlend
.
Colors
[
j
]);
}
}
}
for
(
var
i
=
0
;
i
<
colorBlend
.
Positions
.
Length
-
1
;
i
++)
colorBlend
.
Positions
=
pos
.
ToArray
();
colorBlend
.
Colors
=
colors
.
ToArray
();
outScale
=
newScale
;
break
;
case
SvgGradientSpreadMethod
.
Repeat
:
newScale
=
(
float
)
Math
.
Ceiling
(
scale
);
pos
=
(
from
p
in
colorBlend
.
Positions
select
p
/
newScale
).
ToList
();
colors
=
colorBlend
.
Colors
.
ToList
();
for
(
var
i
=
1
;
i
<
newScale
;
i
++)
{
colorBlend
.
Positions
[
i
]
=
1
-
(
specifiedRadius
/
effectiveRadius
)
*
(
1
-
colorBlend
.
Positions
[
i
]);
pos
.
AddRange
(
from
p
in
colorBlend
.
Positions
select
(
i
+
(
p
<=
0
?
0.001f
:
p
))
/
newScale
);
colors
.
AddRange
(
colorBlend
.
Colors
);
}
colorBlend
.
Positions
=
new
[]
{
0F
}.
Concat
(
colorBlend
.
Positions
).
ToArray
();
colorBlend
.
Colors
=
new
[]
{
colorBlend
.
Colors
.
First
()
}.
Concat
(
colorBlend
.
Colors
).
ToArray
();
colorBlend
.
Positions
=
pos
.
ToArray
();
colorBlend
.
Colors
=
colors
.
ToArray
();
outScale
=
newScale
;
break
;
default
:
outScale
=
1.0f
;
//for (var i = 0; i < colorBlend.Positions.Length - 1; i++)
//{
// colorBlend.Positions[i] = 1 - (1 - colorBlend.Positions[i]) / scale;
//}
//colorBlend.Positions = new[] { 0F }.Concat(colorBlend.Positions).ToArray();
//colorBlend.Colors = new[] { colorBlend.Colors.First() }.Concat(colorBlend.Colors).ToArray();
break
;
}
}
return
colorBlend
;
}
...
...
Source/Paths/CoordinateParser.cs
0 → 100644
View file @
1585c700
using
System
;
using
System.Collections.Generic
;
using
System.Linq
;
using
System.Text
;
using
System.Globalization
;
namespace
Svg
{
internal
class
CoordinateParser
{
private
enum
NumState
{
invalid
,
separator
,
prefix
,
integer
,
decPlace
,
fraction
,
exponent
,
expPrefix
,
expValue
}
private
string
_coords
;
private
int
_pos
=
0
;
private
NumState
_currState
=
NumState
.
separator
;
private
NumState
_newState
=
NumState
.
separator
;
private
int
i
=
0
;
private
bool
_parseWorked
=
true
;
public
int
Position
{
get
{
return
_pos
;
}
}
public
CoordinateParser
(
string
coords
)
{
_coords
=
coords
;
if
(
string
.
IsNullOrEmpty
(
_coords
))
_parseWorked
=
false
;
if
(
char
.
IsLetter
(
coords
[
0
]))
i
++;
}
public
bool
HasMore
{
get
{
return
_parseWorked
;
}
}
private
bool
MarkState
(
bool
state
)
{
_parseWorked
=
state
;
i
++;
return
state
;
}
public
bool
TryGetBool
(
out
bool
result
)
{
while
(
i
<
_coords
.
Length
&&
_parseWorked
)
{
switch
(
_currState
)
{
case
NumState
.
separator
:
if
(
IsCoordSeparator
(
_coords
[
i
]))
{
_newState
=
NumState
.
separator
;
}
else
if
(
_coords
[
i
]
==
'0'
)
{
result
=
false
;
_newState
=
NumState
.
separator
;
_pos
=
i
+
1
;
return
MarkState
(
true
);
}
else
if
(
_coords
[
i
]
==
'1'
)
{
result
=
true
;
_newState
=
NumState
.
separator
;
_pos
=
i
+
1
;
return
MarkState
(
true
);
}
else
{
result
=
false
;
return
MarkState
(
false
);
}
break
;
default
:
result
=
false
;
return
MarkState
(
false
);
}
i
++;
}
result
=
false
;
return
MarkState
(
false
);
}
public
bool
TryGetFloat
(
out
float
result
)
{
while
(
i
<
_coords
.
Length
&&
_parseWorked
)
{
switch
(
_currState
)
{
case
NumState
.
separator
:
if
(
char
.
IsNumber
(
_coords
[
i
]))
{
_newState
=
NumState
.
integer
;
}
else
if
(
IsCoordSeparator
(
_coords
[
i
]))
{
_newState
=
NumState
.
separator
;
}
else
{
switch
(
_coords
[
i
])
{
case
'.'
:
_newState
=
NumState
.
decPlace
;
break
;
case
'+'
:
case
'-'
:
_newState
=
NumState
.
prefix
;
break
;
default
:
_newState
=
NumState
.
invalid
;
break
;
}
}
break
;
case
NumState
.
prefix
:
if
(
char
.
IsNumber
(
_coords
[
i
]))
{
_newState
=
NumState
.
integer
;
}
else
if
(
_coords
[
i
]
==
'.'
)
{
_newState
=
NumState
.
decPlace
;
}
else
{
_newState
=
NumState
.
invalid
;
}
break
;
case
NumState
.
integer
:
if
(
char
.
IsNumber
(
_coords
[
i
]))
{
_newState
=
NumState
.
integer
;
}
else
if
(
IsCoordSeparator
(
_coords
[
i
]))
{
_newState
=
NumState
.
separator
;
}
else
{
switch
(
_coords
[
i
])
{
case
'.'
:
_newState
=
NumState
.
decPlace
;
break
;
case
'E'
:
case
'e'
:
_newState
=
NumState
.
exponent
;
break
;
case
'+'
:
case
'-'
:
_newState
=
NumState
.
prefix
;
break
;
default
:
_newState
=
NumState
.
invalid
;
break
;
}
}
break
;
case
NumState
.
decPlace
:
if
(
char
.
IsNumber
(
_coords
[
i
]))
{
_newState
=
NumState
.
fraction
;
}
else
if
(
IsCoordSeparator
(
_coords
[
i
]))
{
_newState
=
NumState
.
separator
;
}
else
{
switch
(
_coords
[
i
])
{
case
'E'
:
case
'e'
:
_newState
=
NumState
.
exponent
;
break
;
case
'+'
:
case
'-'
:
_newState
=
NumState
.
prefix
;
break
;
default
:
_newState
=
NumState
.
invalid
;
break
;
}
}
break
;
case
NumState
.
fraction
:
if
(
char
.
IsNumber
(
_coords
[
i
]))
{
_newState
=
NumState
.
fraction
;
}
else
if
(
IsCoordSeparator
(
_coords
[
i
]))
{
_newState
=
NumState
.
separator
;
}
else
{
switch
(
_coords
[
i
])
{
case
'.'
:
_newState
=
NumState
.
decPlace
;
break
;
case
'E'
:
case
'e'
:
_newState
=
NumState
.
exponent
;
break
;
case
'+'
:
case
'-'
:
_newState
=
NumState
.
prefix
;
break
;
default
:
_newState
=
NumState
.
invalid
;
break
;
}
}
break
;
case
NumState
.
exponent
:
if
(
char
.
IsNumber
(
_coords
[
i
]))
{
_newState
=
NumState
.
expValue
;
}
else
if
(
IsCoordSeparator
(
_coords
[
i
]))
{
_newState
=
NumState
.
invalid
;
}
else
{
switch
(
_coords
[
i
])
{
case
'+'
:
case
'-'
:
_newState
=
NumState
.
expPrefix
;
break
;
default
:
_newState
=
NumState
.
invalid
;
break
;
}
}
break
;
case
NumState
.
expPrefix
:
if
(
char
.
IsNumber
(
_coords
[
i
]))
{
_newState
=
NumState
.
expValue
;
}
else
{
_newState
=
NumState
.
invalid
;
}
break
;
case
NumState
.
expValue
:
if
(
char
.
IsNumber
(
_coords
[
i
]))
{
_newState
=
NumState
.
expValue
;
}
else
if
(
IsCoordSeparator
(
_coords
[
i
]))
{
_newState
=
NumState
.
separator
;
}
else
{
switch
(
_coords
[
i
])
{
case
'.'
:
_newState
=
NumState
.
decPlace
;
break
;
case
'+'
:
case
'-'
:
_newState
=
NumState
.
prefix
;
break
;
default
:
_newState
=
NumState
.
invalid
;
break
;
}
}
break
;
}
if
(
_newState
<
_currState
)
{
result
=
float
.
Parse
(
_coords
.
Substring
(
_pos
,
i
-
_pos
),
NumberStyles
.
Float
,
CultureInfo
.
InvariantCulture
);
_pos
=
i
;
_currState
=
_newState
;
return
MarkState
(
true
);
}
else
if
(
_newState
!=
_currState
&&
_currState
==
NumState
.
separator
)
{
_pos
=
i
;
}
if
(
_newState
==
NumState
.
invalid
)
{
result
=
float
.
MinValue
;
return
MarkState
(
false
);
}
_currState
=
_newState
;
i
++;
}
if
(
_currState
==
NumState
.
separator
||
!
_parseWorked
||
_pos
>=
_coords
.
Length
)
{
result
=
float
.
MinValue
;
return
MarkState
(
false
);
}
else
{
result
=
float
.
Parse
(
_coords
.
Substring
(
_pos
,
_coords
.
Length
-
_pos
),
NumberStyles
.
Float
,
CultureInfo
.
InvariantCulture
);
_pos
=
_coords
.
Length
;
return
MarkState
(
true
);
}
}
private
static
bool
IsCoordSeparator
(
char
value
)
{
switch
(
value
)
{
case
' '
:
case
'\t'
:
case
'\n'
:
case
'\r'
:
case
','
:
return
true
;
}
return
false
;
}
}
}
Source/Paths/SvgPath.cs
View file @
1585c700
...
...
@@ -38,9 +38,9 @@ namespace Svg
/// Gets or sets the length of the path.
/// </summary>
[
SvgAttribute
(
"pathLength"
)]
public
in
t
PathLength
public
floa
t
PathLength
{
get
{
return
this
.
Attributes
.
GetAttribute
<
in
t
>(
"pathLength"
);
}
get
{
return
this
.
Attributes
.
GetAttribute
<
floa
t
>(
"pathLength"
);
}
set
{
this
.
Attributes
[
"pathLength"
]
=
value
;
}
}
...
...
@@ -81,7 +81,7 @@ namespace Svg
/// <summary>
/// Gets the <see cref="GraphicsPath"/> for this element.
/// </summary>
public
override
GraphicsPath
Path
(
SvgRenderer
renderer
)
public
override
GraphicsPath
Path
(
I
SvgRenderer
renderer
)
{
if
(
this
.
_path
==
null
||
this
.
IsPathDirty
)
{
...
...
@@ -131,24 +131,13 @@ namespace Svg
}
/// <summary>
/// Renders the stroke of the <see cref="SvgVisualElement"/> to the specified <see cref="SvgRenderer"/>
/// Renders the stroke of the <see cref="SvgVisualElement"/> to the specified <see cref="
I
SvgRenderer"/>
/// </summary>
/// <param name="renderer">The <see cref="SvgRenderer"/> object to render to.</param>
protected
internal
override
void
RenderStroke
(
SvgRenderer
renderer
)
/// <param name="renderer">The <see cref="
I
SvgRenderer"/> object to render to.</param>
protected
internal
override
bool
RenderStroke
(
I
SvgRenderer
renderer
)
{
if
(
this
.
Stroke
!=
null
)
{
float
strokeWidth
=
this
.
StrokeWidth
.
ToDeviceValue
(
renderer
,
UnitRenderingType
.
Other
,
this
);
using
(
Pen
pen
=
new
Pen
(
this
.
Stroke
.
GetBrush
(
this
,
renderer
,
this
.
StrokeOpacity
),
strokeWidth
))
{
if
(
this
.
StrokeDashArray
!=
null
&&
this
.
StrokeDashArray
.
Count
>
0
)
{
/* divide by stroke width - GDI behaviour that I don't quite understand yet.*/
pen
.
DashPattern
=
this
.
StrokeDashArray
.
ConvertAll
(
u
=>
u
.
Value
/
((
strokeWidth
<=
0
)
?
1
:
strokeWidth
)).
ToArray
();
}
var
result
=
base
.
RenderStroke
(
renderer
);
var
path
=
this
.
Path
(
renderer
);
renderer
.
DrawPath
(
pen
,
path
);
if
(
this
.
MarkerStart
!=
null
)
{
...
...
@@ -168,8 +157,8 @@ namespace Svg
SvgMarker
marker
=
this
.
OwnerDocument
.
GetElementById
<
SvgMarker
>(
this
.
MarkerEnd
.
ToString
());
marker
.
RenderMarker
(
renderer
,
this
,
path
.
PathPoints
[
path
.
PathPoints
.
Length
-
1
],
path
.
PathPoints
[
path
.
PathPoints
.
Length
-
2
],
path
.
PathPoints
[
path
.
PathPoints
.
Length
-
1
]);
}
}
}
return
result
;
}
public
override
SvgElement
DeepCopy
()
...
...
Prev
1
2
3
4
5
6
Next
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment