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
ceb78a3f
Commit
ceb78a3f
authored
Jul 25, 2014
by
Eric Domke
Browse files
Iteration 1 of tspan functionality
parent
f10b0336
Changes
9
Expand all
Show whitespace changes
Inline
Side-by-side
Source/Paths/SvgClosePathSegment.cs
View file @
ceb78a3f
...
@@ -9,7 +9,7 @@ namespace Svg.Pathing
...
@@ -9,7 +9,7 @@ namespace Svg.Pathing
public
override
void
AddToPath
(
System
.
Drawing
.
Drawing2D
.
GraphicsPath
graphicsPath
)
public
override
void
AddToPath
(
System
.
Drawing
.
Drawing2D
.
GraphicsPath
graphicsPath
)
{
{
// Important for custom line caps. Force the path the close with an explicit line, not just an implicit close of the figure.
// Important for custom line caps. Force the path the close with an explicit line, not just an implicit close of the figure.
if
(
graphicsPath
.
P
athPoints
.
Length
>
1
&&
!
graphicsPath
.
PathPoints
[
0
].
Equals
(
graphicsPath
.
PathPoints
[
graphicsPath
.
PathPoints
.
Length
-
1
]))
if
(
graphicsPath
.
P
ointCount
>
0
&&
!
graphicsPath
.
PathPoints
[
0
].
Equals
(
graphicsPath
.
PathPoints
[
graphicsPath
.
PathPoints
.
Length
-
1
]))
{
{
int
i
=
graphicsPath
.
PathTypes
.
Length
-
1
;
int
i
=
graphicsPath
.
PathTypes
.
Length
-
1
;
while
(
i
>=
0
&&
graphicsPath
.
PathTypes
[
i
]
>
0
)
i
--;
while
(
i
>=
0
&&
graphicsPath
.
PathTypes
[
i
]
>
0
)
i
--;
...
...
Source/Svg.csproj
View file @
ceb78a3f
...
@@ -136,6 +136,7 @@
...
@@ -136,6 +136,7 @@
<Compile
Include=
"Filter Effects\feGaussianBlur\SvgGaussianBlur.cs"
/>
<Compile
Include=
"Filter Effects\feGaussianBlur\SvgGaussianBlur.cs"
/>
<Compile
Include=
"Filter Effects\feMerge\SvgMerge.cs"
/>
<Compile
Include=
"Filter Effects\feMerge\SvgMerge.cs"
/>
<Compile
Include=
"Painting\EnumConverters.cs"
/>
<Compile
Include=
"Painting\EnumConverters.cs"
/>
<Compile
Include=
"SvgContentNode.cs"
/>
<Compile
Include=
"SvgDefinitionDefaults.cs"
/>
<Compile
Include=
"SvgDefinitionDefaults.cs"
/>
<Compile
Include=
"NonSvgElement.cs"
/>
<Compile
Include=
"NonSvgElement.cs"
/>
<Compile
Include=
"SvgUnknownElement.cs"
/>
<Compile
Include=
"SvgUnknownElement.cs"
/>
...
@@ -183,6 +184,7 @@
...
@@ -183,6 +184,7 @@
<Compile
Include=
"DataTypes\SvgUnitConverter.cs"
/>
<Compile
Include=
"DataTypes\SvgUnitConverter.cs"
/>
<Compile
Include=
"SvgTextReader.cs"
/>
<Compile
Include=
"SvgTextReader.cs"
/>
<Compile
Include=
"Text\SvgText.cs"
/>
<Compile
Include=
"Text\SvgText.cs"
/>
<Compile
Include=
"Text\SvgTextBase.cs"
/>
<Compile
Include=
"Text\SvgTextAnchor.cs"
/>
<Compile
Include=
"Text\SvgTextAnchor.cs"
/>
<Compile
Include=
"Text\SvgTextSpan.cs"
/>
<Compile
Include=
"Text\SvgTextSpan.cs"
/>
<Compile
Include=
"Transforms\ISvgTransformable.cs"
/>
<Compile
Include=
"Transforms\ISvgTransformable.cs"
/>
...
...
Source/SvgContentNode.cs
0 → 100644
View file @
ceb78a3f
using
System
;
using
System.Collections.Generic
;
using
System.Linq
;
using
System.Text
;
namespace
Svg
{
public
class
SvgContentNode
:
ISvgNode
{
public
string
Content
{
get
;
set
;
}
}
}
Source/SvgDocument.cs
View file @
ceb78a3f
...
@@ -8,6 +8,7 @@ using System.Drawing.Text;
...
@@ -8,6 +8,7 @@ using System.Drawing.Text;
using
System.IO
;
using
System.IO
;
using
System.Text
;
using
System.Text
;
using
System.Xml
;
using
System.Xml
;
using
System.Linq
;
namespace
Svg
namespace
Svg
{
{
...
@@ -184,7 +185,6 @@ namespace Svg
...
@@ -184,7 +185,6 @@ namespace Svg
using
(
var
reader
=
new
SvgTextReader
(
stream
,
entities
))
using
(
var
reader
=
new
SvgTextReader
(
stream
,
entities
))
{
{
var
elementStack
=
new
Stack
<
SvgElement
>();
var
elementStack
=
new
Stack
<
SvgElement
>();
var
value
=
new
StringBuilder
();
bool
elementEmpty
;
bool
elementEmpty
;
SvgElement
element
=
null
;
SvgElement
element
=
null
;
SvgElement
parent
;
SvgElement
parent
;
...
@@ -218,7 +218,10 @@ namespace Svg
...
@@ -218,7 +218,10 @@ namespace Svg
{
{
parent
=
elementStack
.
Peek
();
parent
=
elementStack
.
Peek
();
if
(
parent
!=
null
&&
element
!=
null
)
if
(
parent
!=
null
&&
element
!=
null
)
{
parent
.
Children
.
Add
(
element
);
parent
.
Children
.
Add
(
element
);
parent
.
Nodes
.
Add
(
element
);
}
}
}
// Push element into stack
// Push element into stack
...
@@ -236,21 +239,24 @@ namespace Svg
...
@@ -236,21 +239,24 @@ namespace Svg
// Pop the element out of the stack
// Pop the element out of the stack
element
=
elementStack
.
Pop
();
element
=
elementStack
.
Pop
();
if
(
value
.
Length
>
0
&&
element
!=
null
)
if
(
element
.
Nodes
.
OfType
<
SvgContentNode
>().
Any
()
)
{
{
element
.
Content
=
value
.
ToString
();
element
.
Content
=
(
from
e
in
element
.
Nodes
select
e
.
Content
).
Aggregate
((
p
,
c
)
=>
p
+
c
);
}
// Reset content value for new element
else
value
.
Length
=
0
;
{
element
.
Nodes
.
Clear
();
// No sense wasting the space where it isn't needed
}
}
break
;
break
;
case
XmlNodeType
.
CDATA
:
case
XmlNodeType
.
CDATA
:
case
XmlNodeType
.
Text
:
case
XmlNodeType
.
Text
:
value
.
Append
(
reader
.
Value
);
element
=
elementStack
.
Peek
();
element
.
Nodes
.
Add
(
new
SvgContentNode
()
{
Content
=
reader
.
Value
});
break
;
break
;
case
XmlNodeType
.
EntityReference
:
case
XmlNodeType
.
EntityReference
:
reader
.
ResolveEntity
();
reader
.
ResolveEntity
();
value
.
Append
(
reader
.
Value
);
element
=
elementStack
.
Peek
();
element
.
Nodes
.
Add
(
new
SvgContentNode
()
{
Content
=
reader
.
Value
});
break
;
break
;
}
}
}
}
...
...
Source/SvgElement.cs
View file @
ceb78a3f
...
@@ -15,7 +15,7 @@ namespace Svg
...
@@ -15,7 +15,7 @@ namespace Svg
/// <summary>
/// <summary>
/// The base class of which all SVG elements are derived from.
/// The base class of which all SVG elements are derived from.
/// </summary>
/// </summary>
public
abstract
class
SvgElement
:
ISvgElement
,
ISvgTransformable
,
ICloneable
public
abstract
class
SvgElement
:
ISvgElement
,
ISvgTransformable
,
ICloneable
,
ISvgNode
{
{
//optimization
//optimization
protected
class
PropertyAttributeTuple
protected
class
PropertyAttributeTuple
...
@@ -42,6 +42,7 @@ namespace Svg
...
@@ -42,6 +42,7 @@ namespace Svg
private
static
readonly
object
_loadEventKey
=
new
object
();
private
static
readonly
object
_loadEventKey
=
new
object
();
private
Matrix
_graphicsMatrix
;
private
Matrix
_graphicsMatrix
;
private
SvgCustomAttributeCollection
_customAttributes
;
private
SvgCustomAttributeCollection
_customAttributes
;
private
List
<
ISvgNode
>
_nodes
=
new
List
<
ISvgNode
>();
/// <summary>
/// <summary>
/// Gets the name of the element.
/// Gets the name of the element.
...
@@ -117,6 +118,11 @@ namespace Svg
...
@@ -117,6 +118,11 @@ namespace Svg
get
{
return
this
.
_children
;
}
get
{
return
this
.
_children
;
}
}
}
public
IList
<
ISvgNode
>
Nodes
{
get
{
return
this
.
_nodes
;
}
}
public
IEnumerable
<
SvgElement
>
Descendants
()
public
IEnumerable
<
SvgElement
>
Descendants
()
{
{
return
this
.
AsEnumerable
().
Descendants
();
return
this
.
AsEnumerable
().
Descendants
();
...
@@ -612,7 +618,7 @@ namespace Svg
...
@@ -612,7 +618,7 @@ namespace Svg
if
(
child
.
Transforms
!=
null
)
if
(
child
.
Transforms
!=
null
)
childPath
.
Transform
(
child
.
Transforms
.
GetMatrix
());
childPath
.
Transform
(
child
.
Transforms
.
GetMatrix
());
path
.
AddPath
(
childPath
,
false
);
if
(
childPath
.
PointCount
>
0
)
path
.
AddPath
(
childPath
,
false
);
}
}
}
}
}
}
...
@@ -921,7 +927,6 @@ namespace Svg
...
@@ -921,7 +927,6 @@ namespace Svg
}
}
#
endregion
graphical
EVENTS
#
endregion
graphical
EVENTS
}
}
public
class
SVGArg
:
EventArgs
public
class
SVGArg
:
EventArgs
...
@@ -1035,10 +1040,16 @@ namespace Svg
...
@@ -1035,10 +1040,16 @@ namespace Svg
public
bool
CtrlKey
;
public
bool
CtrlKey
;
}
}
public
interface
ISvgNode
{
string
Content
{
get
;
}
}
internal
interface
ISvgElement
internal
interface
ISvgElement
{
{
SvgElement
Parent
{
get
;}
SvgElement
Parent
{
get
;}
SvgElementCollection
Children
{
get
;
}
SvgElementCollection
Children
{
get
;
}
IList
<
ISvgNode
>
Nodes
{
get
;
}
void
Render
(
SvgRenderer
renderer
);
void
Render
(
SvgRenderer
renderer
);
}
}
...
...
Source/SvgRenderer.cs
View file @
ceb78a3f
...
@@ -157,6 +157,7 @@ namespace Svg
...
@@ -157,6 +157,7 @@ namespace Svg
StringFormat
format
=
StringFormat
.
GenericTypographic
;
StringFormat
format
=
StringFormat
.
GenericTypographic
;
format
.
SetMeasurableCharacterRanges
(
new
CharacterRange
[]{
new
CharacterRange
(
0
,
text
.
Length
)});
format
.
SetMeasurableCharacterRanges
(
new
CharacterRange
[]{
new
CharacterRange
(
0
,
text
.
Length
)});
format
.
FormatFlags
|=
StringFormatFlags
.
MeasureTrailingSpaces
;
Region
[]
r
=
this
.
_innerGraphics
.
MeasureCharacterRanges
(
text
,
font
,
new
Rectangle
(
0
,
0
,
1000
,
1000
),
format
);
Region
[]
r
=
this
.
_innerGraphics
.
MeasureCharacterRanges
(
text
,
font
,
new
Rectangle
(
0
,
0
,
1000
,
1000
),
format
);
RectangleF
rect
=
r
[
0
].
GetBounds
(
this
.
_innerGraphics
);
RectangleF
rect
=
r
[
0
].
GetBounds
(
this
.
_innerGraphics
);
...
...
Source/Text/SvgText.cs
View file @
ceb78a3f
using
System
;
using
System
;
using
System.Collections.Generic
;
using
System.Collections.Generic
;
using
System.Linq
;
using
System.Text
;
using
System.Text
;
using
System.Text.RegularExpressions
;
using
System.ComponentModel
;
using
System.Drawing
;
using
System.Drawing
;
using
System.Drawing.Drawing2D
;
using
System.Drawing.Drawing2D
;
using
System.Drawing.Text
;
using
Svg.DataTypes
;
using
Svg.DataTypes
;
using
System.Linq
;
namespace
Svg
namespace
Svg
{
{
...
@@ -15,43 +12,12 @@ namespace Svg
...
@@ -15,43 +12,12 @@ namespace Svg
/// The <see cref="SvgText"/> element defines a graphics element consisting of text.
/// The <see cref="SvgText"/> element defines a graphics element consisting of text.
/// </summary>
/// </summary>
[
SvgElement
(
"text"
)]
[
SvgElement
(
"text"
)]
public
class
SvgText
:
Svg
VisualElement
public
class
SvgText
:
Svg
TextBase
{
{
private
SvgUnit
_x
;
private
SvgUnit
_y
;
private
SvgUnit
_dy
;
private
SvgUnit
_dx
;
private
SvgUnit
_letterSpacing
;
private
SvgUnit
_wordSpacing
;
private
SvgUnit
_fontSize
;
private
SvgFontWeight
_fontWeight
;
private
string
_font
;
private
string
_fontFamily
;
private
GraphicsPath
_path
;
private
SvgTextAnchor
_textAnchor
=
SvgTextAnchor
.
Start
;
private
static
readonly
SvgRenderer
_stringMeasure
;
private
const
string
DefaultFontFamily
=
"Times New Roman"
;
/// <summary>
/// <summary>
/// Initializes the <see cref="SvgText"/> class.
/// Initializes the <see cref="SvgText"/> class.
/// </summary>
/// </summary>
static
SvgText
()
public
SvgText
()
:
base
()
{}
{
Bitmap
bitmap
=
new
Bitmap
(
1
,
1
);
_stringMeasure
=
SvgRenderer
.
FromImage
(
bitmap
);
_stringMeasure
.
TextRenderingHint
=
TextRenderingHint
.
AntiAlias
;
}
/// <summary>
/// Initializes a new instance of the <see cref="SvgText"/> class.
/// </summary>
public
SvgText
()
{
this
.
_fontFamily
=
DefaultFontFamily
;
this
.
_fontSize
=
new
SvgUnit
(
0.0f
);
this
.
_dy
=
new
SvgUnit
(
0.0f
);
this
.
_dx
=
new
SvgUnit
(
0.0f
);
}
/// <summary>
/// <summary>
/// Initializes a new instance of the <see cref="SvgText"/> class.
/// Initializes a new instance of the <see cref="SvgText"/> class.
...
@@ -62,427 +28,6 @@ namespace Svg
...
@@ -62,427 +28,6 @@ namespace Svg
this
.
Text
=
text
;
this
.
Text
=
text
;
}
}
/// <summary>
/// Gets or sets the text to be rendered.
/// </summary>
public
virtual
string
Text
{
get
{
return
base
.
Content
;
}
set
{
base
.
Content
=
value
;
this
.
IsPathDirty
=
true
;
this
.
Content
=
value
;
}
}
/// <summary>
/// Gets or sets the text anchor.
/// </summary>
/// <value>The text anchor.</value>
[
SvgAttribute
(
"text-anchor"
)]
public
virtual
SvgTextAnchor
TextAnchor
{
get
{
return
this
.
_textAnchor
;
}
set
{
this
.
_textAnchor
=
value
;
this
.
IsPathDirty
=
true
;
}
}
/// <summary>
/// Gets or sets the X.
/// </summary>
/// <value>The X.</value>
[
SvgAttribute
(
"x"
)]
public
virtual
SvgUnit
X
{
get
{
return
this
.
_x
;
}
set
{
if
(
_x
!=
value
)
{
this
.
_x
=
value
;
this
.
IsPathDirty
=
true
;
OnAttributeChanged
(
new
AttributeEventArgs
{
Attribute
=
"x"
,
Value
=
value
});
}
}
}
/// <summary>
/// Gets or sets the dX.
/// </summary>
/// <value>The dX.</value>
[
SvgAttribute
(
"dx"
)]
public
virtual
SvgUnit
Dx
{
get
{
return
this
.
_dx
;
}
set
{
if
(
_dx
!=
value
)
{
this
.
_dx
=
value
;
this
.
IsPathDirty
=
true
;
OnAttributeChanged
(
new
AttributeEventArgs
{
Attribute
=
"dx"
,
Value
=
value
});
}
}
}
/// <summary>
/// Gets or sets the Y.
/// </summary>
/// <value>The Y.</value>
[
SvgAttribute
(
"y"
)]
public
virtual
SvgUnit
Y
{
get
{
return
this
.
_y
;
}
set
{
if
(
_y
!=
value
)
{
this
.
_y
=
value
;
this
.
IsPathDirty
=
true
;
OnAttributeChanged
(
new
AttributeEventArgs
{
Attribute
=
"y"
,
Value
=
value
});
}
}
}
/// <summary>
/// Gets or sets the dY.
/// </summary>
/// <value>The dY.</value>
[
SvgAttribute
(
"dy"
)]
public
virtual
SvgUnit
Dy
{
get
{
return
this
.
_dy
;
}
set
{
if
(
_dy
!=
value
)
{
this
.
_dy
=
value
;
this
.
IsPathDirty
=
true
;
OnAttributeChanged
(
new
AttributeEventArgs
{
Attribute
=
"dy"
,
Value
=
value
});
}
}
}
/// <summary>
/// Specifies spacing behavior between text characters.
/// </summary>
[
SvgAttribute
(
"letter-spacing"
)]
public
virtual
SvgUnit
LetterSpacing
{
get
{
return
this
.
_letterSpacing
;
}
set
{
this
.
_letterSpacing
=
value
;
this
.
IsPathDirty
=
true
;
}
}
/// <summary>
/// Specifies spacing behavior between words.
/// </summary>
[
SvgAttribute
(
"word-spacing"
)]
public
virtual
SvgUnit
WordSpacing
{
get
{
return
this
.
_wordSpacing
;
}
set
{
this
.
_wordSpacing
=
value
;
this
.
IsPathDirty
=
true
;
}
}
/// <summary>
/// Indicates which font family is to be used to render the text.
/// </summary>
[
SvgAttribute
(
"font-family"
)]
public
virtual
string
FontFamily
{
get
{
return
this
.
_fontFamily
;
}
set
{
this
.
_fontFamily
=
ValidateFontFamily
(
value
);
this
.
IsPathDirty
=
true
;
}
}
/// <summary>
/// Refers to the size of the font from baseline to baseline when multiple lines of text are set solid in a multiline layout environment.
/// </summary>
[
SvgAttribute
(
"font-size"
)]
public
virtual
SvgUnit
FontSize
{
get
{
return
this
.
_fontSize
;
}
set
{
this
.
_fontSize
=
value
;
this
.
IsPathDirty
=
true
;
}
}
/// <summary>
/// Refers to the boldness of the font.
/// </summary>
[
SvgAttribute
(
"font-weight"
)]
public
virtual
SvgFontWeight
FontWeight
{
get
{
return
this
.
_fontWeight
;
}
set
{
this
.
_fontWeight
=
value
;
this
.
IsPathDirty
=
true
;
}
}
/// <summary>
/// Set all font information.
/// </summary>
[
SvgAttribute
(
"font"
)]
public
virtual
string
Font
{
get
{
return
this
.
_font
;
}
set
{
var
parts
=
value
.
Split
(
','
);
foreach
(
var
part
in
parts
)
{
//This deals with setting font size. Looks for either <number>px or <number>pt style="font: bold 16px/normal 'trebuchet ms', verdana, sans-serif;"
Regex
rx
=
new
Regex
(
@"(\d+)+(?=pt|px)"
);
var
res
=
rx
.
Match
(
part
);
if
(
res
.
Success
)
{
int
fontSize
=
10
;
int
.
TryParse
(
res
.
Value
,
out
fontSize
);
this
.
FontSize
=
new
SvgUnit
((
float
)
fontSize
);
}
//this assumes "bold" has spaces around it. e.g.: style="font: bold 16px/normal
rx
=
new
Regex
(
@"\sbold\s"
);
res
=
rx
.
Match
(
part
);
if
(
res
.
Success
)
{
this
.
FontWeight
=
SvgFontWeight
.
bold
;
}
}
var
font
=
ValidateFontFamily
(
value
);
this
.
_fontFamily
=
font
;
this
.
_font
=
font
;
//not sure this is used?
this
.
IsPathDirty
=
true
;
}
}
/// <summary>
/// Gets or sets the fill.
/// </summary>
/// <remarks>
/// <para>Unlike other <see cref="SvgGraphicsElement"/>s, <see cref="SvgText"/> has a default fill of black rather than transparent.</para>
/// </remarks>
/// <value>The fill.</value>
public
override
SvgPaintServer
Fill
{
get
{
return
(
this
.
Attributes
[
"fill"
]
==
null
)
?
new
SvgColourServer
(
Color
.
Black
)
:
(
SvgPaintServer
)
this
.
Attributes
[
"fill"
];
}
set
{
this
.
Attributes
[
"fill"
]
=
value
;
}
}
/// <summary>
/// Returns a <see cref="T:System.String"/> that represents the current <see cref="T:System.Object"/>.
/// </summary>
/// <returns>
/// A <see cref="T:System.String"/> that represents the current <see cref="T:System.Object"/>.
/// </returns>
public
override
string
ToString
()
{
return
this
.
Text
;
}
/// <summary>
/// Gets or sets a value to determine if anti-aliasing should occur when the element is being rendered.
/// </summary>
/// <value></value>
protected
override
bool
RequiresSmoothRendering
{
get
{
return
true
;
}
}
/// <summary>
/// Gets the bounds of the element.
/// </summary>
/// <value>The bounds.</value>
public
override
System
.
Drawing
.
RectangleF
Bounds
{
get
{
return
this
.
Path
.
GetBounds
();
}
}
static
private
RectangleF
MeasureString
(
SvgRenderer
renderer
,
string
text
,
Font
font
)
{
GraphicsPath
p
=
new
GraphicsPath
();
p
.
AddString
(
text
,
font
.
FontFamily
,
0
,
font
.
Size
,
new
PointF
(
0.0f
,
0.0f
),
StringFormat
.
GenericTypographic
);
p
.
Transform
(
renderer
.
Transform
);
return
p
.
GetBounds
();
}
/// <summary>
/// Gets the <see cref="GraphicsPath"/> for this element.
/// </summary>
/// <value></value>
public
override
System
.
Drawing
.
Drawing2D
.
GraphicsPath
Path
{
get
{
// Make sure the path is always null if there is no text
//if there is a TSpan inside of this text element then path should not be null (even if this text is empty!)
if
((
string
.
IsNullOrEmpty
(
this
.
Text
)
||
this
.
Text
.
Trim
().
Length
<
1
)
&&
this
.
Children
.
Where
(
x
=>
x
is
SvgTextSpan
).
Select
(
x
=>
x
as
SvgTextSpan
).
Count
()
==
0
)
return
_path
=
null
;
//NOT SURE WHAT THIS IS ABOUT - Path gets created again anyway - WTF?
// When an empty string is passed to GraphicsPath, it rises an InvalidArgumentException...
if
(
_path
==
null
||
this
.
IsPathDirty
)
{
float
fontSize
=
this
.
FontSize
.
ToDeviceValue
(
this
);
if
(
fontSize
==
0.0f
)
{
fontSize
=
1.0f
;
}
FontStyle
fontWeight
=
(
this
.
FontWeight
==
SvgFontWeight
.
bold
?
FontStyle
.
Bold
:
FontStyle
.
Regular
);
Font
font
=
new
Font
(
this
.
_fontFamily
,
fontSize
,
fontWeight
,
GraphicsUnit
.
Pixel
);
_path
=
new
GraphicsPath
();
_path
.
StartFigure
();
if
(!
string
.
IsNullOrEmpty
(
this
.
Text
))
DrawString
(
_path
,
this
.
X
,
this
.
Y
,
this
.
Dx
,
this
.
Dy
,
font
,
fontSize
,
this
.
Text
);
foreach
(
var
tspan
in
this
.
Children
.
Where
(
x
=>
x
is
SvgTextSpan
).
Select
(
x
=>
x
as
SvgTextSpan
))
{
if
(!
string
.
IsNullOrEmpty
(
tspan
.
Text
))
DrawString
(
_path
,
tspan
.
X
==
SvgUnit
.
Empty
?
this
.
X
:
tspan
.
X
,
tspan
.
Y
==
SvgUnit
.
Empty
?
this
.
Y
:
tspan
.
Y
,
tspan
.
DX
,
tspan
.
DY
,
font
,
fontSize
,
tspan
.
Text
);
}
_path
.
CloseFigure
();
this
.
IsPathDirty
=
false
;
}
return
_path
;
}
protected
set
{
_path
=
value
;
}
}
private
static
string
ValidateFontFamily
(
string
fontFamilyList
)
{
// Split font family list on "," and then trim start and end spaces and quotes.
var
fontParts
=
fontFamilyList
.
Split
(
new
[]
{
','
}).
Select
(
fontName
=>
fontName
.
Trim
(
new
[]
{
'"'
,
' '
,
'\''
}));
var
families
=
System
.
Drawing
.
FontFamily
.
Families
;
// Find a the first font that exists in the list of installed font families.
//styles from IE get sent through as lowercase.
foreach
(
var
f
in
fontParts
.
Where
(
f
=>
families
.
Any
(
family
=>
family
.
Name
.
ToLower
()
==
f
.
ToLower
())))
{
return
f
;
}
// No valid font family found from the list requested.
return
DefaultFontFamily
;
}
private
void
DrawString
(
GraphicsPath
path
,
SvgUnit
x
,
SvgUnit
y
,
SvgUnit
dx
,
SvgUnit
dy
,
Font
font
,
float
fontSize
,
string
text
)
{
PointF
location
=
PointF
.
Empty
;
SizeF
stringBounds
;
lock
(
_stringMeasure
)
{
stringBounds
=
_stringMeasure
.
MeasureString
(
text
,
font
);
}
float
xToDevice
=
x
.
ToDeviceValue
(
this
)
+
dx
.
ToDeviceValue
(
this
);
float
yToDevice
=
y
.
ToDeviceValue
(
this
,
true
)
+
dy
.
ToDeviceValue
(
this
,
true
);
// Minus FontSize because the x/y coords mark the bottom left, not bottom top.
switch
(
this
.
TextAnchor
)
{
case
SvgTextAnchor
.
Start
:
location
=
new
PointF
(
xToDevice
,
yToDevice
-
stringBounds
.
Height
);
break
;
case
SvgTextAnchor
.
Middle
:
location
=
new
PointF
(
xToDevice
-
(
stringBounds
.
Width
/
2
),
yToDevice
-
stringBounds
.
Height
);
break
;
case
SvgTextAnchor
.
End
:
location
=
new
PointF
(
xToDevice
-
stringBounds
.
Width
,
yToDevice
-
stringBounds
.
Height
);
break
;
}
// No way to do letter-spacing or word-spacing, so do manually
if
(
this
.
LetterSpacing
.
Value
>
0.0f
||
this
.
WordSpacing
.
Value
>
0.0f
)
{
// Cut up into words, or just leave as required
string
[]
words
=
(
this
.
WordSpacing
.
Value
>
0.0f
)
?
text
.
Split
(
' '
)
:
new
string
[]
{
text
};
float
wordSpacing
=
this
.
WordSpacing
.
ToDeviceValue
(
this
);
float
letterSpacing
=
this
.
LetterSpacing
.
ToDeviceValue
(
this
);
float
start
=
this
.
X
.
ToDeviceValue
(
this
);
foreach
(
string
word
in
words
)
{
// Only do if there is line spacing, just write the word otherwise
if
(
this
.
LetterSpacing
.
Value
>
0.0f
)
{
char
[]
characters
=
word
.
ToCharArray
();
foreach
(
char
currentCharacter
in
characters
)
{
path
.
AddString
(
currentCharacter
.
ToString
(),
new
FontFamily
(
this
.
_fontFamily
),
(
int
)
font
.
Style
,
fontSize
,
location
,
StringFormat
.
GenericTypographic
);
location
=
new
PointF
(
path
.
GetBounds
().
Width
+
start
+
letterSpacing
,
location
.
Y
);
}
}
else
{
path
.
AddString
(
word
,
new
FontFamily
(
this
.
_fontFamily
),
(
int
)
font
.
Style
,
fontSize
,
location
,
StringFormat
.
GenericTypographic
);
}
// Move the location of the word to be written along
location
=
new
PointF
(
path
.
GetBounds
().
Width
+
start
+
wordSpacing
,
location
.
Y
);
}
}
else
{
if
(!
string
.
IsNullOrEmpty
(
text
))
{
path
.
AddString
(
text
,
new
FontFamily
(
this
.
_fontFamily
),
(
int
)
font
.
Style
,
fontSize
,
location
,
StringFormat
.
GenericTypographic
);
}
}
}
[
SvgAttribute
(
"onchange"
)]
public
event
EventHandler
<
StringArg
>
Change
;
//change
protected
void
OnChange
(
string
newString
,
string
sessionID
)
{
RaiseChange
(
this
,
new
StringArg
{
s
=
newString
,
SessionID
=
sessionID
});
}
protected
void
RaiseChange
(
object
sender
,
StringArg
s
)
{
var
handler
=
Change
;
if
(
handler
!=
null
)
{
handler
(
sender
,
s
);
}
}
#if Net4
public
override
void
RegisterEvents
(
ISvgEventCaller
caller
)
{
//register basic events
base
.
RegisterEvents
(
caller
);
//add change event for text
caller
.
RegisterAction
<
string
,
string
>(
this
.
ID
+
"/onchange"
,
OnChange
);
}
public
override
void
UnregisterEvents
(
ISvgEventCaller
caller
)
{
//unregister base events
base
.
UnregisterEvents
(
caller
);
//unregister change event
caller
.
UnregisterAction
(
this
.
ID
+
"/onchange"
);
}
#endif
public
override
SvgElement
DeepCopy
()
public
override
SvgElement
DeepCopy
()
{
{
return
DeepCopy
<
SvgText
>();
return
DeepCopy
<
SvgText
>();
...
...
Source/Text/SvgTextBase.cs
0 → 100644
View file @
ceb78a3f
This diff is collapsed.
Click to expand it.
Source/Text/SvgTextSpan.cs
View file @
ceb78a3f
...
@@ -8,69 +8,8 @@ using System.Text;
...
@@ -8,69 +8,8 @@ using System.Text;
namespace
Svg
namespace
Svg
{
{
[
SvgElement
(
"tspan"
)]
[
SvgElement
(
"tspan"
)]
public
class
SvgTextSpan
:
Svg
Element
public
class
SvgTextSpan
:
Svg
TextBase
{
{
private
SvgUnit
_x
;
private
SvgUnit
_y
;
private
SvgUnit
_dx
;
private
SvgUnit
_dy
;
/// <summary>
/// Gets or sets the X.
/// </summary>
/// <value>The X.</value>
[
SvgAttribute
(
"x"
)]
public
SvgUnit
X
{
get
{
return
this
.
_x
;
}
set
{
this
.
_x
=
value
;
}
}
/// <summary>
/// Gets or sets the X.
/// </summary>
/// <value>The X.</value>
[
SvgAttribute
(
"y"
)]
public
SvgUnit
Y
{
get
{
return
this
.
_y
;
}
set
{
this
.
_y
=
value
;
}
}
/// <summary>
/// Gets or sets the deltaX from the containing text.
/// </summary>
/// <value>The dX.</value>
[
SvgAttribute
(
"dx"
)]
public
SvgUnit
DX
{
get
{
return
this
.
_dx
;
}
set
{
this
.
_dx
=
value
;
}
}
/// <summary>
/// Gets or sets the deltaY from the containing text.
/// </summary>
/// <value>The dY.</value>
[
SvgAttribute
(
"dy"
)]
public
SvgUnit
DY
{
get
{
return
this
.
_dy
;
}
set
{
this
.
_dy
=
value
;
}
}
/// <summary>
/// Gets or sets the text to be rendered.
/// </summary>
public
virtual
string
Text
{
get
{
return
base
.
Content
;
}
set
{
base
.
Content
=
value
;
this
.
Content
=
value
;
}
}
public
override
SvgElement
DeepCopy
()
public
override
SvgElement
DeepCopy
()
{
{
...
@@ -82,8 +21,8 @@ namespace Svg
...
@@ -82,8 +21,8 @@ namespace Svg
var
newObj
=
base
.
DeepCopy
<
T
>()
as
SvgTextSpan
;
var
newObj
=
base
.
DeepCopy
<
T
>()
as
SvgTextSpan
;
newObj
.
X
=
this
.
X
;
newObj
.
X
=
this
.
X
;
newObj
.
Y
=
this
.
Y
;
newObj
.
Y
=
this
.
Y
;
newObj
.
D
X
=
this
.
D
X
;
newObj
.
D
x
=
this
.
D
x
;
newObj
.
D
Y
=
this
.
D
Y
;
newObj
.
D
y
=
this
.
D
y
;
newObj
.
Text
=
this
.
Text
;
newObj
.
Text
=
this
.
Text
;
return
newObj
;
return
newObj
;
...
...
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