From a0a3011b37eea6556b33a70debd274b936e7cf5c Mon Sep 17 00:00:00 2001 From: cxl Date: Wed, 6 Mar 2019 11:49:57 +0000 Subject: [PATCH] RichText, RichEdit: Added SVG support git-svn-id: svn://ultimatepp.org/upp/trunk@12811 f0d560ea-af0d-0410-9eb7-867de7ffcac7 --- uppsrc/Painter/Painter.h | 2 ++ uppsrc/Painter/SvgParser.cpp | 42 ++++++++++++++++++++++------ uppsrc/Painter/SvgStyle.cpp | 2 +- uppsrc/Painter/src.tpp/SVG_en-us.tpp | 7 ++++- uppsrc/RichEdit/Clip.cpp | 21 ++++++++++---- uppsrc/RichEdit/Editor.cpp | 2 +- uppsrc/RichText/RichImage.cpp | 20 ++++++++++++- uppsrc/RichText/RichText.upp | 3 +- 8 files changed, 80 insertions(+), 19 deletions(-) diff --git a/uppsrc/Painter/Painter.h b/uppsrc/Painter/Painter.h index 7d1d83a5d..991a5a2ca 100644 --- a/uppsrc/Painter/Painter.h +++ b/uppsrc/Painter/Painter.h @@ -466,6 +466,8 @@ Rectf GetSVGBoundingBox(const char *svg); Image RenderSVGImage(Size sz, const char *svg, Event resloader); Image RenderSVGImage(Size sz, const char *svg); +bool IsSVG(const char *svg); + } #endif diff --git a/uppsrc/Painter/SvgParser.cpp b/uppsrc/Painter/SvgParser.cpp index 95c05dd2c..5cd406e3e 100644 --- a/uppsrc/Painter/SvgParser.cpp +++ b/uppsrc/Painter/SvgParser.cpp @@ -384,14 +384,25 @@ void SvgParser::ParseG() { else if(Tag("text")) { StartElement(); - String text = ReadText(); - text.Replace("\n", " "); - text.Replace("\r", ""); - text.Replace("\t", " "); - Font fnt = state.Top().font; - bp.Text(Dbl("x"), Dbl("y") - fnt.GetAscent(), text, fnt); + auto DoText = [&] { + String text = ReadText(); + text.Replace("\n", " "); + text.Replace("\r", ""); + text.Replace("\t", " "); + if(text.GetCount()) { + Font fnt = state.Top().font; + bp.Text(Dbl("x"), Dbl("y") - fnt.GetAscent(), text, fnt); + } + }; + DoText(); + while(Tag("tspan")) { + StartElement(); + DoText(); + FinishElement(); + PassEnd(); + } FinishElement(); - PassEnd(); + PassEnd(); } else if(Tag("g")) { @@ -438,7 +449,8 @@ bool SvgParser::Parse() { SvgParser::SvgParser(const char *svg, Painter& sw) : XmlParser(svg), - sw(sw), bp(sw) + sw(sw), + bp(sw) { Reset(); } @@ -511,4 +523,18 @@ Image RenderSVGImage(Size sz, const char *svg) return RenderSVGImage(sz, svg, Event()); } +bool IsSVG(const char *svg) +{ + try { + XmlParser xml(svg); + while(!xml.IsTag()) + xml.Skip(); + if(xml.Tag("svg")) + return true; + } + catch(XmlError e) { + } + return false; +} + } diff --git a/uppsrc/Painter/SvgStyle.cpp b/uppsrc/Painter/SvgStyle.cpp index f23471315..7406d0110 100644 --- a/uppsrc/Painter/SvgStyle.cpp +++ b/uppsrc/Painter/SvgStyle.cpp @@ -110,7 +110,7 @@ void SvgParser::ProcessValue(const String& key, const String& value_) else if(key == "font-weight") s.font.Bold(findarg(value, "bold", "bolder") || atoi(value) >= 500); - } + } } void SvgParser::Style(const char *style) diff --git a/uppsrc/Painter/src.tpp/SVG_en-us.tpp b/uppsrc/Painter/src.tpp/SVG_en-us.tpp index e826df49d..f9a4c6f66 100644 --- a/uppsrc/Painter/src.tpp/SVG_en-us.tpp +++ b/uppsrc/Painter/src.tpp/SVG_en-us.tpp @@ -1,9 +1,9 @@ topic "SVG support"; -[ $$0,0#00000000000000000000000000000000:Default] [H6;0 $$1,0#05600065144404261032431302351956:begin] [i448;a25;kKO9;2 $$2,0#37138531426314131252341829483370:codeitem] [l288;2 $$3,0#27521748481378242620020725143825:desc] [0 $$4,0#96390100711032703541132217272105:end] +[ $$0,0#00000000000000000000000000000000:Default] [{_}%EN-US [ {{10000@(113.42.0) [s0; [*@(229)4 SVG support]]}}&] [s4; &] @@ -41,4 +41,9 @@ specified in SVG and uses computed bounding box. It is then scaled into [*@3 sz] at maximum size preserving aspect ratio. Use [*@3 resloader] to provide resources like images.&] [s4; &] +[s1;%- &] +[s2;:Upp`:`:IsSVG`(const char`*`):%- [@(0.0.255) bool]_[* IsSVG]([@(0.0.255) const]_[@(0.0.255) c +har]_`*[*@3 svg])&] +[s3; Returns true if [%-*@3 svg] likely contains SVG image.&] +[s4; &] [s0; ]] \ No newline at end of file diff --git a/uppsrc/RichEdit/Clip.cpp b/uppsrc/RichEdit/Clip.cpp index 619b8b128..2347ce00b 100644 --- a/uppsrc/RichEdit/Clip.cpp +++ b/uppsrc/RichEdit/Clip.cpp @@ -1,4 +1,5 @@ #include "RichEdit.h" +#include namespace Upp { @@ -13,7 +14,7 @@ void RichEdit::InsertImage() } String data = LoadFile(fn); StringStream ss(data); - if(!StreamRaster::OpenAny(ss)) { + if(!StreamRaster::OpenAny(ss) && !IsSVG(data)) { Exclamation(NFormat(t_("Unsupported image format in file [* \1%s\1]."), ~imagefs)); return; } @@ -32,12 +33,14 @@ bool RichEdit::Accept(PasteClip& d, RichText& clip, String& fmt) Vector s = GetFiles(d); if(s.GetCount()) { String fn = s[0]; - String ext = ToUpper(GetFileExt(fn)); - if(ext == ".PNG" || ext == ".JPG" || ext == ".JPEG" || ext == ".GIF" || ext == ".TIF" || ext == ".TIFF") { - if(d.Accept()) { - if(StreamRaster::LoadFileAny(fn)) { + String ext = ToLower(GetFileExt(fn)); + if(findarg(ext, ".png", ".jpg", ".jpeg", ".gif", ".tif", ".tiff", ".svg") >= 0) { + if(d.Accept() && GetFileLength(fn) < 17000000) { + String data = LoadFile(fn); + StringStream ss(data); + if(StreamRaster::OpenAny(ss) || ext == ".svg" && IsSVG(LoadFile(fn))) { RichPara p; - p.Cat(CreateRawImageObject(LoadFile(fn)), formatinfo); + p.Cat(CreateRawImageObject(data), formatinfo); clip.Cat(p); fmt = "files"; } @@ -48,6 +51,12 @@ bool RichEdit::Accept(PasteClip& d, RichText& clip, String& fmt) } d.Reject(); } + if(d.Accept("image/x-inkscape-svg")) { + RichPara p; + p.Cat(CreateRawImageObject(~d), formatinfo); + clip.Cat(p); + fmt = "files"; + } if(d.Accept("text/QTF")) { fmt = "text/QTF"; clip = ParseQTF(~d, 0, context); diff --git a/uppsrc/RichEdit/Editor.cpp b/uppsrc/RichEdit/Editor.cpp index 735803108..f6aaad8c0 100644 --- a/uppsrc/RichEdit/Editor.cpp +++ b/uppsrc/RichEdit/Editor.cpp @@ -736,7 +736,7 @@ RichEdit::RichEdit() ClearModify(); Finish(); - imagefs.Type("Images (*.png *.gif *.jpg *.bmp)", "*.png *.gif *.jpg *.bmp"); + imagefs.Type("Images (*.png *.gif *.jpg *.bmp *.svg)", "*.png *.gif *.jpg *.bmp *.svg"); singleline = false; diff --git a/uppsrc/RichText/RichImage.cpp b/uppsrc/RichText/RichImage.cpp index 42226e7cf..d590a9673 100644 --- a/uppsrc/RichText/RichImage.cpp +++ b/uppsrc/RichText/RichImage.cpp @@ -1,4 +1,5 @@ #include "RichText.h" +#include namespace Upp { @@ -24,6 +25,7 @@ String RichImage::GetTypeName(const Value& v) const return "image"; } +// following function pointers are set in CtrlCore (or similar host platform interface package) static String (*sGetImageClip)(const Image& img, const String& fmt); static bool (*sAcceptImage)(PasteClip& clip); static Image (*sGetImage)(PasteClip& clip); @@ -208,7 +210,12 @@ Size RichRawImage::GetPhysicalSize(const Value& data) const One r = StreamRaster::OpenAny(ss); if(r) return r->GetInfo().dots; - return Size(0, 0); + else + if(IsString(data) && IsSVG(~data)) { + Rectf f = GetSVGBoundingBox(~data); + Zoom z = GetRichTextStdScreenZoom(); + return z.d * (Size)f.GetSize() / z.m; + } } Size RichRawImage::GetPixelSize(const Value& data) const @@ -218,6 +225,11 @@ Size RichRawImage::GetPixelSize(const Value& data) const One r = StreamRaster::OpenAny(ss); if(r) return r->GetSize(); + else + if(IsString(data) && IsSVG(~data)) { + Rectf f = GetSVGBoundingBox(~data); + return (Size)f.GetSize(); + } return Size(0, 0); } @@ -236,6 +248,9 @@ void RichRawImage::Paint(const Value& data, Draw& w, Size sz, void *) const else w.DrawImage(0, 0, sz.cx, sz.cy, r->GetImage()); // scale up by Draw to give e.g. PDF chance to store unscaled } + else + if(IsString(data) && IsSVG(~data)) + w.DrawImage(0, 0, RenderSVGImage(sz, ~data)); } Image RichRawImage::ToImage(const Value& data, Size sz, void *) const @@ -247,6 +262,9 @@ Image RichRawImage::ToImage(const Value& data, Size sz, void *) const Image x = r->GetImage(); return Rescale(x, sz); } + else + if(IsString(data) && IsSVG(~data)) + return RenderSVGImage(sz, ~data); return Null; } diff --git a/uppsrc/RichText/RichText.upp b/uppsrc/RichText/RichText.upp index 6f8d7a8fb..776df8f03 100644 --- a/uppsrc/RichText/RichText.upp +++ b/uppsrc/RichText/RichText.upp @@ -2,7 +2,8 @@ description "Rich-text data structures and painting, including RTF and HTML expo uses plugin\png, - Draw; + Draw, + Painter; file RichText.h options(BUILDER_OPTION) PCH,