diff options
author | Michael Meeks <michael.meeks@suse.com> | 2012-10-09 12:22:23 +0100 |
---|---|---|
committer | Michael Meeks <michael.meeks@suse.com> | 2012-11-06 11:58:16 +0000 |
commit | 44cfc7cb6533d827fd2d6e586d92c61d7d7f7a70 (patch) | |
tree | cfca2fb5cd4676d7d55648fe11105753c2178d5d /svgio | |
parent | eff92f2501cf070cd912508b2ccc3c0108d0327c (diff) |
re-base on ALv2 code. Includes (at least) relevant parts of:
linecap: Reintegrating finished LineCap feature
Patch contributed by Regina Henschel
http://svn.apache.org/viewvc?view=revision&revision=1232507
Patches contributed by Sven Jacobi
impress212: #i81610# fixed animation export
http://svn.apache.org/viewvc?view=revision&revision=1167620
impress212: drawinglayer gbuild environment changes
http://svn.apache.org/viewvc?view=revision&revision=1167627
http://svn.apache.org/viewvc?view=revision&revision=1167628
impress212: DffPropSet -> minor code improvements, removing table
http://svn.apache.org/viewvc?view=revision&revision=1167634
impress212: #158494# fixed excel import (text rotation)
http://svn.apache.org/viewvc?view=revision&revision=1167638
Patches contributed by Armin Le Grand
Svg: Reintegrated Svg replacement from /branches/alg/svgreplavement
http://svn.apache.org/viewvc?view=revision&revision=1220836
#118728# changed indentifying definitions for Svg file detection
http://svn.apache.org/viewvc?view=revision&revision=1229961
#118838# LineGeometry creation for complicated cases optimized to
create single Polygons
http://svn.apache.org/viewvc?view=revision&revision=1236232
#119176# corrected file type detection for SVG for svg files
without xml header
http://svn.apache.org/viewvc?view=revision&revision=1309445
#118728# Extended Svg file detection
http://svn.apache.org/viewvc?view=revision&revision=1230531
#118529# solve break converters and convert commands for OLEs and images
http://svn.apache.org/viewvc?view=revision&revision=1186168
svg: added WaE changes from branch svgreplacement to trunc
http://svn.apache.org/viewvc?view=revision&revision=1222974
svg: corrected missing member initialization
http://svn.apache.org/viewvc?view=revision&revision=1226134
fix for #118525#: Using primitives for chart sub-geometry visualisation
http://svn.apache.org/viewvc?view=revision&revision=1226879
#118898# Adapted ImpGraphic::ImplGetBitmap to correctly convert
metafiles to bitmapEx ...
http://svn.apache.org/viewvc?view=revision&revision=1293316
fix for #118525#: removed no longer used variable maOriginalMapMode, one
more exception eliminated
http://svn.apache.org/viewvc?view=revision&revision=1227097
#16758# Added buffering to the VDev usages of the VclProcessor2D derivates...
http://svn.apache.org/viewvc?view=revision&revision=1229521
#116758# Secured VDev buffer device to Vcl deinit
http://svn.apache.org/viewvc?view=revision&revision=1230574
#116758# added remembering allocated VDevs for VDevBuffer to be able to also
delete these when vcl goes down; it should never happen, but You never know
http://svn.apache.org/viewvc?view=revision&revision=1230927
#118730# Changed SvgClipPathNode to use MaskPrimitive2D for primitive
representation instead of TransparencePrimitive2D
http://svn.apache.org/viewvc?view=revision&revision=1231198
#118822# secured 3D geometry creation (slices) by subdividing the 2D
source polyPolygon early
http://svn.apache.org/viewvc?view=revision&revision=1234749
#118829# enhanced Svg gradient quality, obstacles avoided
http://svn.apache.org/viewvc?view=revision&revision=1235361
#118834# Unified usage of TextBreakupHelper as single tooling class
for i18n text primitive breakup
http://svn.apache.org/viewvc?view=revision&revision=1236110
#118853# added square pixel size limit to conversion of
TransparencePrimitive2D to Metafile action
http://svn.apache.org/viewvc?view=revision&revision=1237656
#118824# coreccted mirroring and boundrect when the graphicmanager
is used for bitmap output
http://svn.apache.org/viewvc?view=revision&revision=1240097
#115092# Corrected VclProcessor2D::RenderPolygonStrokePrimitive2D for
various optimization scenarios
http://svn.apache.org/viewvc?view=revision&revision=1241434
#118783# Corrected errors in ID strings, corrected Svg line/fill export,
corrected polygon close state
http://svn.apache.org/viewvc?view=revision&revision=1232006
#118796# corrected null-pointer usage in SVG text exporter
http://svn.apache.org/viewvc?view=revision&revision=1240262
#118729# Use GraphicStreamUrl and GraphicUrl to allow multi image
import with linked graphics, too
http://svn.apache.org/viewvc?view=revision&revision=1229962
#118898# corrected error in GDIMetaFile::GetBoundRect in handling
MetaFloatTransparentAction
http://svn.apache.org/viewvc?view=revision&revision=1293349
#118855# Corrected handling of possibly created empty clipRegions
after PolyPolygon clipping
http://svn.apache.org/viewvc?view=revision&revision=1237725
#115962# Better (but not yet optimal, see comments in task) handling
of MetaFloatTransparentAction in PDF export
http://svn.apache.org/viewvc?view=revision&revision=1241078
IP clearance: #118466# This patch removes librsvg, libcroco, libgsf, ...
http://svn.apache.org/viewvc?view=revision&revision=1200879
118779# Added svg content streaming in/out to ImpGraphic stream operators
http://svn.apache.org/viewvc?view=revision&revision=1231908
linecap: correctons for WaE and mac drawing
http://svn.apache.org/viewvc?view=revision&revision=1232793
svg: uses current system Dpi for Svg replacement image creation
http://svn.apache.org/viewvc?view=revision&revision=1233948
Patches contributed by Mathias Bauer (and others)
gnumake4 work variously
http://svn.apache.org/viewvc?view=revision&revision=1394326
http://svn.apache.org/viewvc?view=revision&revision=1396797
http://svn.apache.org/viewvc?view=revision&revision=1397315
http://svn.apache.org/viewvc?view=revision&revision=1394326
Remove duplicate header includes.
cws mba34issues01: #i117720#: convert assertion into warning
http://svn.apache.org/viewvc?view=revision&revision=1172352
118485 - Styles for OLEs are not saved. Submitted by Armin Le Grand.
http://svn.apache.org/viewvc?view=revision&revision=1182166
cws mba34issues01: #i117714#: remove assertion
http://svn.apache.org/viewvc?view=revision&revision=1172357
Patch contributed by Jurgen Schmidt
add some additional checks to ensure proper reading operations
http://svn.apache.org/viewvc?view=revision&revision=1209022
mostly prefer our stream / bounds checking work.
Patches contributed by Herbert Duerr
#i118816# add clarifying comment regarding Font::*Color*() methods
http://svn.apache.org/viewvc?view=revision&revision=1233833
extend macro->string handling for empty strings
http://svn.apache.org/viewvc?view=revision&revision=1175801
avoid magic constants for SALCOLOR_NONE
http://svn.apache.org/viewvc?view=revision&revision=1177543
initialize slant properly in ImplFontMetricData constructor (author=iorsh)
http://svn.apache.org/viewvc?view=revision&revision=1177551
#i118675# make check for extension updates more stable
http://svn.apache.org/viewvc?view=revision&revision=1214797
#a118617# remove VBasicEventListener.dll binary
There are no known users depending on its CLSID
http://svn.apache.org/viewvc?view=revision&revision=1203697
Patches contributed by Ariel Constenla-Haile
Fix build breaker on Linux/gcc
http://svn.apache.org/viewvc?view=revision&revision=1221104
Fix crash when trying to instantiate css.graphic.GraphicRasterizer_RSVG
http://svn.apache.org/viewvc?view=revision&revision=1215559
Patches contributed by Oliver-Rainer Wittmann
sw34bf06: #i117962# - method <SwFlyFrm::IsPaint(..)> - consider
instances of <SwFlyDrawObj>
http://svn.apache.org/viewvc?view=revision&revision=1172120
sw34bf06: #i117783# - Writer's implementation of XPagePrintable -
apply print settings to new printing routines
http://svn.apache.org/viewvc?view=revision&revision=1172115
gnumake4 work variously from Hans-Joachim Lankenau
http://svn.apache.org/viewvc?view=revision&revision=1397315
http://svn.apache.org/viewvc?view=revision&revision=1396797
http://svn.apache.org/viewvc?view=revision&revision=1396782
http://svn.apache.org/viewvc?view=revision&revision=1394707
plus some amount of re-splitting of legacy headers.
Patch contributed by Pavel Janik
WaE: Remove unused variables.
http://svn.apache.org/viewvc?view=revision&revision=1230697
Patches contributed by Takashi Ono
mingwport35: i#117795: MinGW port fix for vcl2gnumake
http://svn.apache.org/viewvc?view=revision&revision=1172091
mingwport35: i#117795: MinGW port fix for vcl2gnumake
http://svn.apache.org/viewvc?view=revision&revision=1172091
Patch contributed by Christian Lippka
impress212: #i98044# re enable Text menu for outline and title shapes
http://svn.apache.org/viewvc?view=revision&revision=1167639
Patch contributed by Andre Fischer
118674: Made category B code optional and disabled by default.
http://svn.apache.org/viewvc?view=revision&revision=1215131
118881: Ignore empty paragraphs after bullets.
http://svn.apache.org/viewvc?view=revision&revision=1296205
Patches contributed by Philipp Lohmann
ooo340fixes: #i117780# use rtl allocator
http://svn.apache.org/viewvc?view=revision&revision=1172087
ooo34gsl02: #i117807# fix an off by one error (index actually
inside the pfb section header)
http://svn.apache.org/viewvc?view=revision&revision=1167576
various cleanups, related compilation fixes, warning cleanups, re-working
of obsolete stl template pieces to use boost instead, changed string
classes, re-adapt KDE about data, about dialog, fixing warnings,
and other fixes & improvements.
Disable svg import / render for about/ branding code-paths for now.
Restore full icon theme set.
Remove OS/2 conditionals and sources.
Remove conflicting gtk/full-screen monitors support.
Retain existing svg rasterizer files - temporarily disabled.
Standardize stringificaiton and fixup dllpostfix issues.
Rename SvgGradientHelper::== to equalTo to avoid overloading issues.
Use the flat GdiPlus API for LineCaps calls.
Diffstat (limited to 'svgio')
73 files changed, 15039 insertions, 0 deletions
diff --git a/svgio/Library_svgio.mk b/svgio/Library_svgio.mk new file mode 100644 index 000000000000..bc4ddb61131f --- /dev/null +++ b/svgio/Library_svgio.mk @@ -0,0 +1,86 @@ +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# This file incorporates work covered by the following license notice: +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed +# with this work for additional information regarding copyright +# ownership. The ASF licenses this file to you under the Apache +# License, Version 2.0 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.apache.org/licenses/LICENSE-2.0 . +# + +$(eval $(call gb_Library_Library,svgio)) + +$(eval $(call gb_Library_set_componentfile,svgio,svgio/svgio)) + +$(eval $(call gb_Library_use_package,svgio)) + +$(eval $(call gb_Library_add_precompiled_header,svgio,$(SRCDIR)/svgio/inc/pch/precompiled_svgio)) + +$(eval $(call gb_Library_use_sdk_api,svgio)) + +$(eval $(call gb_Library_set_include,svgio,\ + $$(INCLUDE) \ + -I$(SRCDIR)/svgio/inc \ +)) + +$(eval $(call gb_Library_add_defs,svgio,\ + -DSVGIO_DLLIMPLEMENTATION \ +)) + +$(eval $(call gb_Library_use_libraries,svgio,\ + basegfx \ + drawinglayer \ + comphelper \ + cppu \ + cppuhelper \ + sal \ + tl \ + sax \ + vcl \ + svt \ +)) + +$(eval $(call gb_Library_add_exception_objects,svgio,\ + svgio/source/svgreader/svgcharacternode \ + svgio/source/svgreader/svgcirclenode \ + svgio/source/svgreader/svgclippathnode \ + svgio/source/svgreader/svgdocument \ + svgio/source/svgreader/svgdocumenthandler \ + svgio/source/svgreader/svgellipsenode \ + svgio/source/svgreader/svggnode \ + svgio/source/svgreader/svggradientnode \ + svgio/source/svgreader/svggradientstopnode \ + svgio/source/svgreader/svgimagenode \ + svgio/source/svgreader/svglinenode \ + svgio/source/svgreader/svgmarkernode \ + svgio/source/svgreader/svgmasknode \ + svgio/source/svgreader/svgnode \ + svgio/source/svgreader/svgpaint \ + svgio/source/svgreader/svgpathnode \ + svgio/source/svgreader/svgpatternnode \ + svgio/source/svgreader/svgpolynode \ + svgio/source/svgreader/svgrectnode \ + svgio/source/svgreader/svgstyleattributes \ + svgio/source/svgreader/svgstylenode \ + svgio/source/svgreader/svgsvgnode \ + svgio/source/svgreader/svgsymbolnode \ + svgio/source/svgreader/svgtextnode \ + svgio/source/svgreader/svgtoken \ + svgio/source/svgreader/svgtrefnode \ + svgio/source/svgreader/svgtools \ + svgio/source/svgreader/svgtextpathnode \ + svgio/source/svgreader/svgtspannode \ + svgio/source/svgreader/svgusenode \ + svgio/source/svguno/svguno \ + svgio/source/svguno/xsvgparser \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/svgio/Makefile b/svgio/Makefile new file mode 100644 index 000000000000..0997e628485b --- /dev/null +++ b/svgio/Makefile @@ -0,0 +1,14 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +module_directory:=$(dir $(realpath $(firstword $(MAKEFILE_LIST)))) + +include $(module_directory)/../solenv/gbuild/partial_build.mk + +# vim: set noet sw=4 ts=4: diff --git a/svgio/Module_svgio.mk b/svgio/Module_svgio.mk new file mode 100644 index 000000000000..f1b3b7b88c53 --- /dev/null +++ b/svgio/Module_svgio.mk @@ -0,0 +1,26 @@ +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# This file incorporates work covered by the following license notice: +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed +# with this work for additional information regarding copyright +# ownership. The ASF licenses this file to you under the Apache +# License, Version 2.0 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.apache.org/licenses/LICENSE-2.0 . +# + +$(eval $(call gb_Module_Module,svgio)) + +$(eval $(call gb_Module_add_targets,svgio,\ + Library_svgio \ + Package_inc \ +)) + +# vim: set noet ts=4 sw=4: diff --git a/svgio/Package_inc.mk b/svgio/Package_inc.mk new file mode 100644 index 000000000000..5aed79891b7e --- /dev/null +++ b/svgio/Package_inc.mk @@ -0,0 +1,50 @@ +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# This file incorporates work covered by the following license notice: +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed +# with this work for additional information regarding copyright +# ownership. The ASF licenses this file to you under the Apache +# License, Version 2.0 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.apache.org/licenses/LICENSE-2.0 . +# + +$(eval $(call gb_Package_Package,svgio_inc,$(SRCDIR)/svgio/inc)) +$(eval $(call gb_Package_add_file,svgio_inc,inc/svgio/svgiodllapi.h,svgio/svgiodllapi.h)) +$(eval $(call gb_Package_add_file,svgio_inc,inc/svgio/svgreader/svgcharacternode.hxx,svgio/svgreader/svgcharacternode.hxx)) +$(eval $(call gb_Package_add_file,svgio_inc,inc/svgio/svgreader/svgcirclenode.hxx,svgio/svgreader/svgcirclenode.hxx)) +$(eval $(call gb_Package_add_file,svgio_inc,inc/svgio/svgreader/svgclippathnode.hxx,svgio/svgreader/svgclippathnode.hxx)) +$(eval $(call gb_Package_add_file,svgio_inc,inc/svgio/svgreader/svgdocument.hxx,svgio/svgreader/svgdocument.hxx)) +$(eval $(call gb_Package_add_file,svgio_inc,inc/svgio/svgreader/svgdocumenthandler.hxx,svgio/svgreader/svgdocumenthandler.hxx)) +$(eval $(call gb_Package_add_file,svgio_inc,inc/svgio/svgreader/svgellipsenode.hxx,svgio/svgreader/svgellipsenode.hxx)) +$(eval $(call gb_Package_add_file,svgio_inc,inc/svgio/svgreader/svggnode.hxx,svgio/svgreader/svggnode.hxx)) +$(eval $(call gb_Package_add_file,svgio_inc,inc/svgio/svgreader/svggradientnode.hxx,svgio/svgreader/svggradientnode.hxx)) +$(eval $(call gb_Package_add_file,svgio_inc,inc/svgio/svgreader/svggradientstopnode.hxx,svgio/svgreader/svggradientstopnode.hxx)) +$(eval $(call gb_Package_add_file,svgio_inc,inc/svgio/svgreader/svgimagenode.hxx,svgio/svgreader/svgimagenode.hxx)) +$(eval $(call gb_Package_add_file,svgio_inc,inc/svgio/svgreader/svglinenode.hxx,svgio/svgreader/svglinenode.hxx)) +$(eval $(call gb_Package_add_file,svgio_inc,inc/svgio/svgreader/svgnode.hxx,svgio/svgreader/svgnode.hxx)) +$(eval $(call gb_Package_add_file,svgio_inc,inc/svgio/svgreader/svgmarkernode.hxx,svgio/svgreader/svgmarkernode.hxx)) +$(eval $(call gb_Package_add_file,svgio_inc,inc/svgio/svgreader/svgmasknode.hxx,svgio/svgreader/svgmasknode.hxx)) +$(eval $(call gb_Package_add_file,svgio_inc,inc/svgio/svgreader/svgpaint.hxx,svgio/svgreader/svgpaint.hxx)) +$(eval $(call gb_Package_add_file,svgio_inc,inc/svgio/svgreader/svgpathnode.hxx,svgio/svgreader/svgpathnode.hxx)) +$(eval $(call gb_Package_add_file,svgio_inc,inc/svgio/svgreader/svgpatternnode.hxx,svgio/svgreader/svgpatternnode.hxx)) +$(eval $(call gb_Package_add_file,svgio_inc,inc/svgio/svgreader/svgpolynode.hxx,svgio/svgreader/svgpolynode.hxx)) +$(eval $(call gb_Package_add_file,svgio_inc,inc/svgio/svgreader/svgrectnode.hxx,svgio/svgreader/svgrectnode.hxx)) +$(eval $(call gb_Package_add_file,svgio_inc,inc/svgio/svgreader/svgstyleattributes.hxx,svgio/svgreader/svgstyleattributes.hxx)) +$(eval $(call gb_Package_add_file,svgio_inc,inc/svgio/svgreader/svgstylenode.hxx,svgio/svgreader/svgstylenode.hxx)) +$(eval $(call gb_Package_add_file,svgio_inc,inc/svgio/svgreader/svgsvgnode.hxx,svgio/svgreader/svgsvgnode.hxx)) +$(eval $(call gb_Package_add_file,svgio_inc,inc/svgio/svgreader/svgsymbolnode.hxx,svgio/svgreader/svgsymbolnode.hxx)) +$(eval $(call gb_Package_add_file,svgio_inc,inc/svgio/svgreader/svgtextnode.hxx,svgio/svgreader/svgtextnode.hxx)) +$(eval $(call gb_Package_add_file,svgio_inc,inc/svgio/svgreader/svgtoken.hxx,svgio/svgreader/svgtoken.hxx)) +$(eval $(call gb_Package_add_file,svgio_inc,inc/svgio/svgreader/svgtrefnode.hxx,svgio/svgreader/svgtrefnode.hxx)) +$(eval $(call gb_Package_add_file,svgio_inc,inc/svgio/svgreader/svgtools.hxx,svgio/svgreader/svgtools.hxx)) +$(eval $(call gb_Package_add_file,svgio_inc,inc/svgio/svgreader/svgtextpathnode.hxx,svgio/svgreader/svgtextpathnode.hxx)) +$(eval $(call gb_Package_add_file,svgio_inc,inc/svgio/svgreader/svgtspannode.hxx,svgio/svgreader/svgtspannode.hxx)) +$(eval $(call gb_Package_add_file,svgio_inc,inc/svgio/svgreader/svgusenode.hxx,svgio/svgreader/svgusenode.hxx)) diff --git a/svgio/inc/pch/precompiled_svgio.cxx b/svgio/inc/pch/precompiled_svgio.cxx new file mode 100644 index 000000000000..db5227c1d1b0 --- /dev/null +++ b/svgio/inc/pch/precompiled_svgio.cxx @@ -0,0 +1,22 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "precompiled_svgio.hxx" + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svgio/inc/pch/precompiled_svgio.hxx b/svgio/inc/pch/precompiled_svgio.hxx new file mode 100644 index 000000000000..e694392e65be --- /dev/null +++ b/svgio/inc/pch/precompiled_svgio.hxx @@ -0,0 +1,25 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +// MARKER(update_precomp.py): Generated on 2006-09-01 17:49:30.796084 + +#ifdef PRECOMPILED_HEADERS +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svgio/inc/svgio/svgiodllapi.h b/svgio/inc/svgio/svgiodllapi.h new file mode 100644 index 000000000000..c28ff1192427 --- /dev/null +++ b/svgio/inc/svgio/svgiodllapi.h @@ -0,0 +1,33 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#ifndef INCLUDED_SVGIODLLAPI_H +#define INCLUDED_SVGIODLLAPI_H + +#include "sal/types.h" + +#if defined(SVGIO_DLLIMPLEMENTATION) +#define SVGIO_DLLPUBLIC SAL_DLLPUBLIC_EXPORT +#else +#define SVGIO_DLLPUBLIC SAL_DLLPUBLIC_IMPORT +#endif +#define SVGIO_DLLPRIVATE SAL_DLLPRIVATE + +#endif /* INCLUDED_SVGIODLLAPI_H */ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svgio/inc/svgio/svgreader/svgcharacternode.hxx b/svgio/inc/svgio/svgreader/svgcharacternode.hxx new file mode 100644 index 000000000000..55d056aadd52 --- /dev/null +++ b/svgio/inc/svgio/svgreader/svgcharacternode.hxx @@ -0,0 +1,184 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_SVGIO_SVGREADER_SVGCHARACTERNODE_HXX +#define INCLUDED_SVGIO_SVGREADER_SVGCHARACTERNODE_HXX + +#include <svgio/svgiodllapi.h> +#include <svgio/svgreader/svgnode.hxx> + +////////////////////////////////////////////////////////////////////////////// +// predefines + +namespace drawinglayer { namespace primitive2d { class TextSimplePortionPrimitive2D; }} + +////////////////////////////////////////////////////////////////////////////// + +namespace svgio +{ + namespace svgreader + { + class SvgTextPositions + { + private: + SvgNumberVector maX; + SvgNumberVector maY; + SvgNumberVector maDx; + SvgNumberVector maDy; + SvgNumberVector maRotate; + SvgNumber maTextLength; + + /// bitfield + bool mbLengthAdjust : 1; // true = spacing, false = spacingAndGlyphs + + public: + SvgTextPositions(); + + void parseTextPositionAttributes(const rtl::OUString& rTokenName, SVGToken aSVGToken, const rtl::OUString& aContent); + + /// X content + const SvgNumberVector& getX() const { return maX; } + void setX(const SvgNumberVector& aX) { maX = aX; } + + /// Y content + const SvgNumberVector& getY() const { return maY; } + void setY(const SvgNumberVector& aY) { maY = aY; } + + /// Dx content + const SvgNumberVector& getDx() const { return maDx; } + void setDx(const SvgNumberVector& aDx) { maDx = aDx; } + + /// Dy content + const SvgNumberVector& getDy() const { return maDy; } + void setDy(const SvgNumberVector& aDy) { maDy = aDy; } + + /// Rotate content + const SvgNumberVector& getRotate() const { return maRotate; } + void setRotate(const SvgNumberVector& aRotate) { maRotate = aRotate; } + + /// TextLength content + const SvgNumber& getTextLength() const { return maTextLength; } + void setTextLength(const SvgNumber& rTextLength = SvgNumber()) { maTextLength = rTextLength; } + + /// LengthAdjust content + bool getLengthAdjust() const { return mbLengthAdjust; } + void setLengthAdjust(bool bNew) { mbLengthAdjust = bNew; } + }; + } // end of namespace svgreader +} // end of namespace svgio + +////////////////////////////////////////////////////////////////////////////// + +namespace svgio +{ + namespace svgreader + { + class SvgTextPosition + { + private: + SvgTextPosition* mpParent; + ::std::vector< double > maX; + ::std::vector< double > maY; + ::std::vector< double > maRotate; + double mfTextLength; + + // absolute, current, advancing position + basegfx::B2DPoint maPosition; + + // advancing rotation index + sal_uInt32 mnRotationIndex; + + /// bitfield + bool mbLengthAdjust : 1; // true = spacing, false = spacingAndGlyphs + bool mbAbsoluteX : 1; + bool mbAbsoluteY : 1; + + public: + SvgTextPosition( + SvgTextPosition* pParent, + const InfoProvider& rInfoProvider, + const SvgTextPositions& rSvgTextPositions); + + // data read access + const SvgTextPosition* getParent() const { return mpParent; } + const ::std::vector< double >& getX() const { return maX; } + const ::std::vector< double >& getY() const { return maY; } + double getTextLength() const { return mfTextLength; } + bool getLengthAdjust() const { return mbLengthAdjust; } + bool getAbsoluteX() const { return mbAbsoluteX; } + bool getAbsoluteY() const { return mbAbsoluteY; } + + // get/set absolute, current, advancing position + const basegfx::B2DPoint& getPosition() const { return maPosition; } + void setPosition(const basegfx::B2DPoint& rNew) { maPosition = rNew; } + + // rotation handling + bool isRotated() const; + double consumeRotation(); + }; + } // end of namespace svgreader +} // end of namespace svgio + +////////////////////////////////////////////////////////////////////////////// + +namespace svgio +{ + namespace svgreader + { + class SvgCharacterNode : public SvgNode + { + private: + /// the string data + rtl::OUString maText; + + /// local helpers + drawinglayer::primitive2d::TextSimplePortionPrimitive2D* createSimpleTextPrimitive( + SvgTextPosition& rSvgTextPosition, + const SvgStyleAttributes& rSvgStyleAttributes) const; + void decomposeTextWithStyle( + drawinglayer::primitive2d::Primitive2DSequence& rTarget, + SvgTextPosition& rSvgTextPosition, + const SvgStyleAttributes& rSvgStyleAttributes) const; + + public: + SvgCharacterNode( + SvgDocument& rDocument, + SvgNode* pParent, + const rtl::OUString& rText); + virtual ~SvgCharacterNode(); + + virtual const SvgStyleAttributes* getSvgStyleAttributes() const; + virtual void decomposeText(drawinglayer::primitive2d::Primitive2DSequence& rTarget, SvgTextPosition& rSvgTextPosition) const; + void whiteSpaceHandling(); + void addGap(); + void concatenate(const rtl::OUString& rText); + + /// Text content + const rtl::OUString& getText() const { return maText; } + }; + } // end of namespace svgreader +} // end of namespace svgio + +////////////////////////////////////////////////////////////////////////////// + +#endif //INCLUDED_SVGIO_SVGREADER_SVGCHARACTERNODE_HXX + +// eof + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svgio/inc/svgio/svgreader/svgcirclenode.hxx b/svgio/inc/svgio/svgreader/svgcirclenode.hxx new file mode 100644 index 000000000000..ddfde9caab00 --- /dev/null +++ b/svgio/inc/svgio/svgreader/svgcirclenode.hxx @@ -0,0 +1,80 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_SVGIO_SVGREADER_SVGCIRCLENODE_HXX +#define INCLUDED_SVGIO_SVGREADER_SVGCIRCLENODE_HXX + +#include <svgio/svgiodllapi.h> +#include <svgio/svgreader/svgnode.hxx> +#include <svgio/svgreader/svgstyleattributes.hxx> + +////////////////////////////////////////////////////////////////////////////// + +namespace svgio +{ + namespace svgreader + { + class SvgCircleNode : public SvgNode + { + private: + /// use styles + SvgStyleAttributes maSvgStyleAttributes; + + /// variable scan values, dependent of given XAttributeList + SvgNumber maCx; + SvgNumber maCy; + SvgNumber maR; + basegfx::B2DHomMatrix* mpaTransform; + + public: + SvgCircleNode( + SvgDocument& rDocument, + SvgNode* pParent); + virtual ~SvgCircleNode(); + + virtual const SvgStyleAttributes* getSvgStyleAttributes() const; + virtual void parseAttribute(const rtl::OUString& rTokenName, SVGToken aSVGToken, const rtl::OUString& aContent); + virtual void decomposeSvgNode(drawinglayer::primitive2d::Primitive2DSequence& rTarget, bool bReferenced) const; + + /// Cx content, set if found in current context + const SvgNumber& getCx() const { return maCx; } + void setCx(const SvgNumber& rCx = SvgNumber()) { maCx = rCx; } + + /// Cy content, set if found in current context + const SvgNumber& getCy() const { return maCy; } + void setCy(const SvgNumber& rCy = SvgNumber()) { maCy = rCy; } + + /// R content, set if found in current context + const SvgNumber& getR() const { return maR; } + void setR(const SvgNumber& rR = SvgNumber()) { maR = rR; } + + /// transform content, set if found in current context + const basegfx::B2DHomMatrix* getTransform() const { return mpaTransform; } + void setTransform(const basegfx::B2DHomMatrix* pMatrix = 0) { if(mpaTransform) delete mpaTransform; mpaTransform = 0; if(pMatrix) mpaTransform = new basegfx::B2DHomMatrix(*pMatrix); } + }; + } // end of namespace svgreader +} // end of namespace svgio + +////////////////////////////////////////////////////////////////////////////// + +#endif //INCLUDED_SVGIO_SVGREADER_SVGCIRCLENODE_HXX + +// eof + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svgio/inc/svgio/svgreader/svgclippathnode.hxx b/svgio/inc/svgio/svgreader/svgclippathnode.hxx new file mode 100644 index 000000000000..95d485ac5dad --- /dev/null +++ b/svgio/inc/svgio/svgreader/svgclippathnode.hxx @@ -0,0 +1,73 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_SVGIO_SVGREADER_SVGCLIPPATHNODE_HXX +#define INCLUDED_SVGIO_SVGREADER_SVGCLIPPATHNODE_HXX + +#include <svgio/svgiodllapi.h> +#include <svgio/svgreader/svgnode.hxx> +#include <svgio/svgreader/svgstyleattributes.hxx> + +////////////////////////////////////////////////////////////////////////////// + +namespace svgio +{ + namespace svgreader + { + class SvgClipPathNode : public SvgNode + { + private: + /// use styles + SvgStyleAttributes maSvgStyleAttributes; + + /// variable scan values, dependent of given XAttributeList + basegfx::B2DHomMatrix* mpaTransform; + SvgUnits maClipPathUnits; + + public: + SvgClipPathNode( + SvgDocument& rDocument, + SvgNode* pParent); + virtual ~SvgClipPathNode(); + + virtual const SvgStyleAttributes* getSvgStyleAttributes() const; + virtual void parseAttribute(const rtl::OUString& rTokenName, SVGToken aSVGToken, const rtl::OUString& aContent); + virtual void decomposeSvgNode(drawinglayer::primitive2d::Primitive2DSequence& rTarget, bool bReferenced) const; + + /// apply contained clipPath to given geometry + void apply(drawinglayer::primitive2d::Primitive2DSequence& rTarget) const; + + /// clipPathUnits content + SvgUnits getClipPathUnits() const { return maClipPathUnits; } + void setClipPathUnits(const SvgUnits aClipPathUnits) { maClipPathUnits = aClipPathUnits; } + + /// transform content + const basegfx::B2DHomMatrix* getTransform() const { return mpaTransform; } + void setTransform(const basegfx::B2DHomMatrix* pMatrix = 0) { if(mpaTransform) delete mpaTransform; mpaTransform = 0; if(pMatrix) mpaTransform = new basegfx::B2DHomMatrix(*pMatrix); } + }; + } // end of namespace svgreader +} // end of namespace svgio + +////////////////////////////////////////////////////////////////////////////// + +#endif //INCLUDED_SVGIO_SVGREADER_SVGCLIPPATHNODE_HXX + +// eof + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svgio/inc/svgio/svgreader/svgdocument.hxx b/svgio/inc/svgio/svgreader/svgdocument.hxx new file mode 100644 index 000000000000..ae30fe40b73d --- /dev/null +++ b/svgio/inc/svgio/svgreader/svgdocument.hxx @@ -0,0 +1,90 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_SVGIO_SVGREADER_SVGDOCUMENT_HXX +#define INCLUDED_SVGIO_SVGREADER_SVGDOCUMENT_HXX + +#include <svgio/svgiodllapi.h> +#include <boost/utility.hpp> +#include <svgio/svgreader/svgnode.hxx> + +////////////////////////////////////////////////////////////////////////////// + +namespace svgio +{ + namespace svgreader + { + class SvgDocument : private boost::noncopyable + { + private: + /// the document hierarchy with all root nodes + SvgNodeVector maNodes; + + /// the absolute path of the Svg file in progress (if available) + const rtl::OUString maAbsolutePath; + + /// hash mapper to find nodes by their id + typedef boost::unordered_map< const rtl::OUString, const SvgNode*, + rtl::OUStringHash, + ::std::equal_to< ::rtl::OUString > > IdTokenMapper; + typedef std::pair< const rtl::OUString, const SvgNode* > IdTokenValueType; + IdTokenMapper maIdTokenMapperList; + + /// hash mapper to find css styles by their id + typedef boost::unordered_map< const rtl::OUString, const SvgStyleAttributes*, rtl::OUStringHash, ::std::equal_to< ::rtl::OUString > > IdStyleTokenMapper; + typedef std::pair< const rtl::OUString, const SvgStyleAttributes* > IdStyleTokenValueType; + IdStyleTokenMapper maIdStyleTokenMapperList; + + public: + SvgDocument(const rtl::OUString& rAbsolutePath); + ~SvgDocument(); + + /// append anopther root node, ownership changes + void appendNode(SvgNode* pNode); + + /// add/remove nodes with Id to mapper + void addSvgNodeToMapper(const rtl::OUString& rStr, const SvgNode& rNode); + void removeSvgNodeFromMapper(const rtl::OUString& rStr); + + /// find a node by it's Id + bool hasSvgNodesById() const { return !maIdTokenMapperList.empty(); } + const SvgNode* findSvgNodeById(const rtl::OUString& rStr) const; + + /// add/remove styles to mapper + void addSvgStyleAttributesToMapper(const rtl::OUString& rStr, const SvgStyleAttributes& rSvgStyleAttributes); + void removeSvgStyleAttributesFromMapper(const rtl::OUString& rStr); + + /// find a style by it's Id + bool hasSvgStyleAttributesById() const { return !maIdStyleTokenMapperList.empty(); } + const SvgStyleAttributes* findSvgStyleAttributesById(const rtl::OUString& rStr) const; + + /// data read access + const SvgNodeVector& getSvgNodeVector() const { return maNodes; } + const rtl::OUString& getAbsolutePath() const { return maAbsolutePath; } + }; + } // end of namespace svgreader +} // end of namespace svgio + +////////////////////////////////////////////////////////////////////////////// + +#endif //INCLUDED_SVGIO_SVGREADER_SVGDOCUMENT_HXX + +// eof + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svgio/inc/svgio/svgreader/svgdocumenthandler.hxx b/svgio/inc/svgio/svgreader/svgdocumenthandler.hxx new file mode 100644 index 000000000000..04ced2ec1cc3 --- /dev/null +++ b/svgio/inc/svgio/svgreader/svgdocumenthandler.hxx @@ -0,0 +1,75 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_SVGIO_SVGREADER_SVGDOCUMENTHANDLER_HXX +#define INCLUDED_SVGIO_SVGREADER_SVGDOCUMENTHANDLER_HXX + +#include <svgio/svgiodllapi.h> +#include <com/sun/star/xml/sax/XDocumentHandler.hpp> +#include <svgio/svgreader/svgdocument.hxx> + +////////////////////////////////////////////////////////////////////////////// +// predefines + +namespace svgio { namespace svgreader { class SvgCharacterNode; }} + +////////////////////////////////////////////////////////////////////////////// + +namespace svgio +{ + namespace svgreader + { + class SvgDocHdl : public cppu::WeakImplHelper1< com::sun::star::xml::sax::XDocumentHandler > + { + private: + // the complete SVG Document + SvgDocument maDocument; + + // current node for parsing + SvgNode* mpTarget; + + // text collector string stack for css styles + std::vector< rtl::OUString > maCssContents; + + public: + SvgDocHdl(const rtl::OUString& rAbsolutePath); + ~SvgDocHdl(); + + // Methods XDocumentHandler + virtual void SAL_CALL startDocument( ) throw (com::sun::star::xml::sax::SAXException, com::sun::star::uno::RuntimeException); + virtual void SAL_CALL endDocument( ) throw (com::sun::star::xml::sax::SAXException, com::sun::star::uno::RuntimeException); + virtual void SAL_CALL startElement( const ::rtl::OUString& aName, const com::sun::star::uno::Reference< com::sun::star::xml::sax::XAttributeList >& xAttribs ) throw (com::sun::star::xml::sax::SAXException, com::sun::star::uno::RuntimeException); + virtual void SAL_CALL endElement( const ::rtl::OUString& aName ) throw (com::sun::star::xml::sax::SAXException, com::sun::star::uno::RuntimeException); + virtual void SAL_CALL characters( const ::rtl::OUString& aChars ) throw (com::sun::star::xml::sax::SAXException, com::sun::star::uno::RuntimeException); + virtual void SAL_CALL ignorableWhitespace( const ::rtl::OUString& aWhitespaces ) throw (com::sun::star::xml::sax::SAXException, com::sun::star::uno::RuntimeException); + virtual void SAL_CALL processingInstruction( const ::rtl::OUString& aTarget, const ::rtl::OUString& aData ) throw (com::sun::star::xml::sax::SAXException, com::sun::star::uno::RuntimeException); + virtual void SAL_CALL setDocumentLocator( const com::sun::star::uno::Reference< com::sun::star::xml::sax::XLocator >& xLocator ) throw (com::sun::star::xml::sax::SAXException, com::sun::star::uno::RuntimeException); + + const SvgDocument& getSvgDocument() const { return maDocument; } + }; + } // end of namespace svgreader +} // end of namespace svgio + +////////////////////////////////////////////////////////////////////////////// + +#endif //INCLUDED_SVGIO_SVGREADER_SVGDOCUMENTHANDLER_HXX + +// eof + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svgio/inc/svgio/svgreader/svgellipsenode.hxx b/svgio/inc/svgio/svgreader/svgellipsenode.hxx new file mode 100644 index 000000000000..5e501c666a87 --- /dev/null +++ b/svgio/inc/svgio/svgreader/svgellipsenode.hxx @@ -0,0 +1,85 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_SVGIO_SVGREADER_SVGELLIPSENODE_HXX +#define INCLUDED_SVGIO_SVGREADER_SVGELLIPSENODE_HXX + +#include <svgio/svgiodllapi.h> +#include <svgio/svgreader/svgnode.hxx> +#include <svgio/svgreader/svgstyleattributes.hxx> + +////////////////////////////////////////////////////////////////////////////// + +namespace svgio +{ + namespace svgreader + { + class SvgEllipseNode : public SvgNode + { + private: + /// use styles + SvgStyleAttributes maSvgStyleAttributes; + + /// variable scan values, dependent of given XAttributeList + SvgNumber maCx; + SvgNumber maCy; + SvgNumber maRx; + SvgNumber maRy; + basegfx::B2DHomMatrix* mpaTransform; + + public: + SvgEllipseNode( + SvgDocument& rDocument, + SvgNode* pParent); + virtual ~SvgEllipseNode(); + + virtual const SvgStyleAttributes* getSvgStyleAttributes() const; + virtual void parseAttribute(const rtl::OUString& rTokenName, SVGToken aSVGToken, const rtl::OUString& aContent); + virtual void decomposeSvgNode(drawinglayer::primitive2d::Primitive2DSequence& rTarget, bool bReferenced) const; + + /// Cx content, set if found in current context + const SvgNumber& getCx() const { return maCx; } + void setCx(const SvgNumber& rCx = SvgNumber()) { maCx = rCx; } + + /// Cy content, set if found in current context + const SvgNumber& getCy() const { return maCy; } + void setCy(const SvgNumber& rCy = SvgNumber()) { maCy = rCy; } + + /// Rx content, set if found in current context + const SvgNumber& getRx() const { return maRx; } + void setRx(const SvgNumber& rRx = SvgNumber()) { maRx = rRx; } + + /// Ry content, set if found in current context + const SvgNumber& getRy() const { return maRy; } + void setRy(const SvgNumber& rRy = SvgNumber()) { maRy = rRy; } + + /// transform content, set if found in current context + const basegfx::B2DHomMatrix* getTransform() const { return mpaTransform; } + void setTransform(const basegfx::B2DHomMatrix* pMatrix = 0) { if(mpaTransform) delete mpaTransform; mpaTransform = 0; if(pMatrix) mpaTransform = new basegfx::B2DHomMatrix(*pMatrix); } + }; + } // end of namespace svgreader +} // end of namespace svgio + +////////////////////////////////////////////////////////////////////////////// + +#endif //INCLUDED_SVGIO_SVGREADER_SVGELLIPSENODE_HXX + +// eof + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svgio/inc/svgio/svgreader/svggnode.hxx b/svgio/inc/svgio/svgreader/svggnode.hxx new file mode 100644 index 000000000000..0bd334dd9257 --- /dev/null +++ b/svgio/inc/svgio/svgreader/svggnode.hxx @@ -0,0 +1,66 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_SVGIO_SVGREADER_SVGGNODE_HXX +#define INCLUDED_SVGIO_SVGREADER_SVGGNODE_HXX + +#include <svgio/svgiodllapi.h> +#include <svgio/svgreader/svgnode.hxx> +#include <svgio/svgreader/svgstyleattributes.hxx> + +////////////////////////////////////////////////////////////////////////////// + +namespace svgio +{ + namespace svgreader + { + class SvgGNode : public SvgNode + { + private: + /// use styles + SvgStyleAttributes maSvgStyleAttributes; + + /// variable scan values, dependent of given XAttributeList + basegfx::B2DHomMatrix* mpaTransform; + + public: + SvgGNode( + SVGToken aType, + SvgDocument& rDocument, + SvgNode* pParent); + virtual ~SvgGNode(); + + virtual const SvgStyleAttributes* getSvgStyleAttributes() const; + virtual void parseAttribute(const rtl::OUString& rTokenName, SVGToken aSVGToken, const rtl::OUString& aContent); + virtual void decomposeSvgNode(drawinglayer::primitive2d::Primitive2DSequence& rTarget, bool bReferenced) const; + + /// transform content + const basegfx::B2DHomMatrix* getTransform() const { return mpaTransform; } + void setTransform(const basegfx::B2DHomMatrix* pMatrix = 0) { if(mpaTransform) delete mpaTransform; mpaTransform = 0; if(pMatrix) mpaTransform = new basegfx::B2DHomMatrix(*pMatrix); } + }; + } // end of namespace svgreader +} // end of namespace svgio + +////////////////////////////////////////////////////////////////////////////// + +#endif //INCLUDED_SVGIO_SVGREADER_SVGGNODE_HXX + +// eof + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svgio/inc/svgio/svgreader/svggradientnode.hxx b/svgio/inc/svgio/svgreader/svggradientnode.hxx new file mode 100644 index 000000000000..7e9e336bf229 --- /dev/null +++ b/svgio/inc/svgio/svgreader/svggradientnode.hxx @@ -0,0 +1,137 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_SVGIO_SVGREADER_SVGGRADIENTNODE_HXX +#define INCLUDED_SVGIO_SVGREADER_SVGGRADIENTNODE_HXX + +#include <svgio/svgiodllapi.h> +#include <svgio/svgreader/svgnode.hxx> +#include <svgio/svgreader/svgstyleattributes.hxx> +#include <drawinglayer/primitive2d/svggradientprimitive2d.hxx> + +////////////////////////////////////////////////////////////////////////////// + +namespace svgio +{ + namespace svgreader + { + class SvgGradientNode : public SvgNode + { + private: + /// use styles + SvgStyleAttributes maSvgStyleAttributes; + + /// linear gradient values + SvgNumber maX1; + SvgNumber maY1; + SvgNumber maX2; + SvgNumber maY2; + + /// radial gradient values + SvgNumber maCx; + SvgNumber maCy; + SvgNumber maR; + SvgNumber maFx; + SvgNumber maFy; + + /// variable scan values, dependent of given XAttributeList + SvgUnits maGradientUnits; + drawinglayer::primitive2d::SpreadMethod maSpreadMethod; + basegfx::B2DHomMatrix* mpaGradientTransform; + + /// link to another gradient used as style. If maXLink + /// is set, the node can be fetched on demand by using + // tryToFindLink (buffered) + rtl::OUString maXLink; + const SvgGradientNode* mpXLink; + + /// link on demand + void tryToFindLink(); + + public: + SvgGradientNode( + SVGToken aType, + SvgDocument& rDocument, + SvgNode* pParent); + virtual ~SvgGradientNode(); + + virtual const SvgStyleAttributes* getSvgStyleAttributes() const; + virtual void parseAttribute(const rtl::OUString& rTokenName, SVGToken aSVGToken, const rtl::OUString& aContent); + + /// collect gradient stop entries + void collectGradientEntries(drawinglayer::primitive2d::SvgGradientEntryVector& aVector) const; + + /// x1 content + const SvgNumber getX1() const; + void setX1(const SvgNumber& rX1 = SvgNumber()) { maX1 = rX1; } + + /// y1 content + const SvgNumber getY1() const; + void setY1(const SvgNumber& rY1 = SvgNumber()) { maY1 = rY1; } + + /// x2 content + const SvgNumber getX2() const; + void setX2(const SvgNumber& rX2 = SvgNumber()) { maX2 = rX2; } + + /// y2 content + const SvgNumber getY2() const; + void setY2(const SvgNumber& rY2 = SvgNumber()) { maY2 = rY2; } + + /// Cx content + const SvgNumber getCx() const; + void setCx(const SvgNumber& rCx = SvgNumber()) { maCx = rCx; } + + /// Cy content + const SvgNumber getCy() const; + void setCy(const SvgNumber& rCy = SvgNumber()) { maCy = rCy; } + + /// R content + const SvgNumber getR() const; + void setR(const SvgNumber& rR = SvgNumber()) { maR = rR; } + + /// Fx content + const SvgNumber* getFx() const; + void setFx(const SvgNumber& rFx = SvgNumber()) { maFx = rFx; } + + /// Fy content + const SvgNumber* getFy() const; + void setFy(const SvgNumber& rFy = SvgNumber()) { maFy = rFy; } + + /// gradientUnits content + SvgUnits getGradientUnits() const { return maGradientUnits; } + void setGradientUnits(const SvgUnits aGradientUnits) { maGradientUnits = aGradientUnits; } + + /// SpreadMethod content + drawinglayer::primitive2d::SpreadMethod getSpreadMethod() const { return maSpreadMethod; } + void setSpreadMethod(const drawinglayer::primitive2d::SpreadMethod aSpreadMethod) { maSpreadMethod = aSpreadMethod; } + + /// transform content, set if found in current context + const basegfx::B2DHomMatrix* getGradientTransform() const; + void setGradientTransform(const basegfx::B2DHomMatrix* pMatrix = 0); + }; + } // end of namespace svgreader +} // end of namespace svgio + +////////////////////////////////////////////////////////////////////////////// + +#endif //INCLUDED_SVGIO_SVGREADER_SVGGRADIENTNODE_HXX + +// eof + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svgio/inc/svgio/svgreader/svggradientstopnode.hxx b/svgio/inc/svgio/svgreader/svggradientstopnode.hxx new file mode 100644 index 000000000000..274b25e61891 --- /dev/null +++ b/svgio/inc/svgio/svgreader/svggradientstopnode.hxx @@ -0,0 +1,64 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_SVGIO_SVGREADER_SVGGRADIENTSTOPNODE_HXX +#define INCLUDED_SVGIO_SVGREADER_SVGGRADIENTSTOPNODE_HXX + +#include <svgio/svgiodllapi.h> +#include <svgio/svgreader/svgnode.hxx> +#include <svgio/svgreader/svgstyleattributes.hxx> + +////////////////////////////////////////////////////////////////////////////// + +namespace svgio +{ + namespace svgreader + { + class SvgGradientStopNode : public SvgNode + { + private: + /// use styles + SvgStyleAttributes maSvgStyleAttributes; + + /// local attributes + SvgNumber maOffset; + + public: + SvgGradientStopNode( + SvgDocument& rDocument, + SvgNode* pParent); + virtual ~SvgGradientStopNode(); + + virtual const SvgStyleAttributes* getSvgStyleAttributes() const; + virtual void parseAttribute(const rtl::OUString& rTokenName, SVGToken aSVGToken, const rtl::OUString& aContent); + + /// offset content + const SvgNumber getOffset() const { return maOffset; } + void setOffset(const SvgNumber& rOffset = SvgNumber()) { maOffset = rOffset; } + }; + } // end of namespace svgreader +} // end of namespace svgio + +////////////////////////////////////////////////////////////////////////////// + +#endif //INCLUDED_SVGIO_SVGREADER_SVGGRADIENTSTOPNODE_HXX + +// eof + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svgio/inc/svgio/svgreader/svgimagenode.hxx b/svgio/inc/svgio/svgreader/svgimagenode.hxx new file mode 100644 index 000000000000..afdf886ab2c3 --- /dev/null +++ b/svgio/inc/svgio/svgreader/svgimagenode.hxx @@ -0,0 +1,99 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_SVGIO_SVGREADER_SVGIMAGENODE_HXX +#define INCLUDED_SVGIO_SVGREADER_SVGIMAGENODE_HXX + +#include <svgio/svgiodllapi.h> +#include <svgio/svgreader/svgnode.hxx> +#include <svgio/svgreader/svgstyleattributes.hxx> + +////////////////////////////////////////////////////////////////////////////// + +namespace svgio +{ + namespace svgreader + { + class SvgImageNode : public SvgNode + { + private: + /// use styles + SvgStyleAttributes maSvgStyleAttributes; + + /// variable scan values, dependent of given XAttributeList + SvgAspectRatio maSvgAspectRatio; + basegfx::B2DHomMatrix* mpaTransform; + SvgNumber maX; + SvgNumber maY; + SvgNumber maWidth; + SvgNumber maHeight; + + rtl::OUString maXLink; // internal link + rtl::OUString maUrl; // external link + + rtl::OUString maMimeType; // mimetype and + rtl::OUString maData; // base64 data + + public: + SvgImageNode( + SvgDocument& rDocument, + SvgNode* pParent); + virtual ~SvgImageNode(); + + virtual const SvgStyleAttributes* getSvgStyleAttributes() const; + virtual void parseAttribute(const rtl::OUString& rTokenName, SVGToken aSVGToken, const rtl::OUString& aContent); + virtual void decomposeSvgNode(drawinglayer::primitive2d::Primitive2DSequence& rTarget, bool bReferenced) const; + + /// SvgAspectRatio content + const SvgAspectRatio& getSvgAspectRatio() const { return maSvgAspectRatio; } + void setSvgAspectRatio(const SvgAspectRatio& rSvgAspectRatio = SvgAspectRatio()) { maSvgAspectRatio = rSvgAspectRatio; } + + /// transform content, set if found in current context + const basegfx::B2DHomMatrix* getTransform() const { return mpaTransform; } + void setTransform(const basegfx::B2DHomMatrix* pMatrix = 0) { if(mpaTransform) delete mpaTransform; mpaTransform = 0; if(pMatrix) mpaTransform = new basegfx::B2DHomMatrix(*pMatrix); } + + /// x content, set if found in current context + const SvgNumber& getX() const { return maX; } + void setX(const SvgNumber& rX = SvgNumber()) { maX = rX; } + + /// y content, set if found in current context + const SvgNumber& getY() const { return maY; } + void setY(const SvgNumber& rY = SvgNumber()) { maY = rY; } + + /// width content, set if found in current context + const SvgNumber& getWidth() const { return maWidth; } + void setWidth(const SvgNumber& rWidth = SvgNumber()) { maWidth = rWidth; } + + /// height content, set if found in current context + const SvgNumber& getHeight() const { return maHeight; } + void setHeight(const SvgNumber& rHeight = SvgNumber()) { maHeight = rHeight; } + + /// XLink access + const rtl::OUString& getXLink() const { return maXLink; } + }; + } // end of namespace svgreader +} // end of namespace svgio + +////////////////////////////////////////////////////////////////////////////// + +#endif //INCLUDED_SVGIO_SVGREADER_SVGIMAGENODE_HXX + +// eof + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svgio/inc/svgio/svgreader/svglinenode.hxx b/svgio/inc/svgio/svgreader/svglinenode.hxx new file mode 100644 index 000000000000..4ee18b7bfa32 --- /dev/null +++ b/svgio/inc/svgio/svgreader/svglinenode.hxx @@ -0,0 +1,85 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_SVGIO_SVGREADER_SVGLINENODE_HXX +#define INCLUDED_SVGIO_SVGREADER_SVGLINENODE_HXX + +#include <svgio/svgiodllapi.h> +#include <svgio/svgreader/svgnode.hxx> +#include <svgio/svgreader/svgstyleattributes.hxx> + +////////////////////////////////////////////////////////////////////////////// + +namespace svgio +{ + namespace svgreader + { + class SvgLineNode : public SvgNode + { + private: + /// use styles + SvgStyleAttributes maSvgStyleAttributes; + + /// variable scan values, dependent of given XAttributeList + SvgNumber maX1; + SvgNumber maY1; + SvgNumber maX2; + SvgNumber maY2; + basegfx::B2DHomMatrix* mpaTransform; + + public: + SvgLineNode( + SvgDocument& rDocument, + SvgNode* pParent); + virtual ~SvgLineNode(); + + virtual const SvgStyleAttributes* getSvgStyleAttributes() const; + virtual void parseAttribute(const rtl::OUString& rTokenName, SVGToken aSVGToken, const rtl::OUString& aContent); + virtual void decomposeSvgNode(drawinglayer::primitive2d::Primitive2DSequence& rTarget, bool bReferenced) const; + + /// X1 content, set if found in current context + const SvgNumber& getX1() const { return maX1; } + void setX1(const SvgNumber& rX1 = SvgNumber()) { maX1 = rX1; } + + /// Y1 content, set if found in current context + const SvgNumber& getY1() const { return maY1; } + void setY1(const SvgNumber& rY1 = SvgNumber()) { maY1 = rY1; } + + /// X2 content, set if found in current context + const SvgNumber& getX2() const { return maX2; } + void setX2(const SvgNumber& rX2 = SvgNumber()) { maX2 = rX2; } + + /// Y2 content, set if found in current context + const SvgNumber& getY2() const { return maY2; } + void setY2(const SvgNumber& rY2 = SvgNumber()) { maY2 = rY2; } + + /// transform content, set if found in current context + const basegfx::B2DHomMatrix* getTransform() const { return mpaTransform; } + void setTransform(const basegfx::B2DHomMatrix* pMatrix = 0) { if(mpaTransform) delete mpaTransform; mpaTransform = 0; if(pMatrix) mpaTransform = new basegfx::B2DHomMatrix(*pMatrix); } + }; + } // end of namespace svgreader +} // end of namespace svgio + +////////////////////////////////////////////////////////////////////////////// + +#endif //INCLUDED_SVGIO_SVGREADER_SVGLINENODE_HXX + +// eof + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svgio/inc/svgio/svgreader/svgmarkernode.hxx b/svgio/inc/svgio/svgreader/svgmarkernode.hxx new file mode 100644 index 000000000000..947f5099bd3a --- /dev/null +++ b/svgio/inc/svgio/svgreader/svgmarkernode.hxx @@ -0,0 +1,123 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_SVGIO_SVGREADER_SVGMARKERNODE_HXX +#define INCLUDED_SVGIO_SVGREADER_SVGMARKERNODE_HXX + +#include <svgio/svgiodllapi.h> +#include <svgio/svgreader/svgnode.hxx> +#include <svgio/svgreader/svgstyleattributes.hxx> + +////////////////////////////////////////////////////////////////////////////// + +namespace svgio +{ + namespace svgreader + { + class SvgMarkerNode : public SvgNode + { + public: + enum MarkerUnits + { + strokeWidth, + userSpaceOnUse + }; + + private: + /// buffered decomposition + drawinglayer::primitive2d::Primitive2DSequence aPrimitives; + + /// use styles + SvgStyleAttributes maSvgStyleAttributes; + + /// variable scan values, dependent of given XAttributeList + basegfx::B2DRange* mpViewBox; + SvgAspectRatio maSvgAspectRatio; + SvgNumber maRefX; + SvgNumber maRefY; + MarkerUnits maMarkerUnits; + SvgNumber maMarkerWidth; + SvgNumber maMarkerHeight; + double mfAngle; + + /// bitfield + bool mbOrientAuto : 1; // true == on, false == fAngle valid + + public: + SvgMarkerNode( + SvgDocument& rDocument, + SvgNode* pParent); + virtual ~SvgMarkerNode(); + + virtual const SvgStyleAttributes* getSvgStyleAttributes() const; + virtual void parseAttribute(const rtl::OUString& rTokenName, SVGToken aSVGToken, const rtl::OUString& aContent); + + /// get marker primitives buffered, uses decomposeSvgNode internally + const drawinglayer::primitive2d::Primitive2DSequence& getMarkerPrimitives() const; + + /// InfoProvider support for % values + virtual const basegfx::B2DRange* getCurrentViewPort() const; + + /// viewBox content + const basegfx::B2DRange* getViewBox() const { return mpViewBox; } + void setViewBox(const basegfx::B2DRange* pViewBox = 0) { if(mpViewBox) delete mpViewBox; mpViewBox = 0; if(pViewBox) mpViewBox = new basegfx::B2DRange(*pViewBox); } + + /// SvgAspectRatio content + const SvgAspectRatio& getSvgAspectRatio() const { return maSvgAspectRatio; } + void setSvgAspectRatio(const SvgAspectRatio& rSvgAspectRatio = SvgAspectRatio()) { maSvgAspectRatio = rSvgAspectRatio; } + + /// RefX content, set if found in current context + const SvgNumber& getRefX() const { return maRefX; } + void setRefX(const SvgNumber& rRefX = SvgNumber()) { maRefX = rRefX; } + + /// RefY content, set if found in current context + const SvgNumber& getRefY() const { return maRefY; } + void setRefY(const SvgNumber& rRefY = SvgNumber()) { maRefY = rRefY; } + + /// MarkerUnits content + MarkerUnits getMarkerUnits() const { return maMarkerUnits; } + void setMarkerUnits(const MarkerUnits aMarkerUnits) { maMarkerUnits = aMarkerUnits; } + + /// MarkerWidth content, set if found in current context + const SvgNumber& getMarkerWidth() const { return maMarkerWidth; } + void setMarkerWidth(const SvgNumber& rMarkerWidth = SvgNumber()) { maMarkerWidth = rMarkerWidth; } + + /// MarkerHeight content, set if found in current context + const SvgNumber& getMarkerHeight() const { return maMarkerHeight; } + void setMarkerHeight(const SvgNumber& rMarkerHeight = SvgNumber()) { maMarkerHeight = rMarkerHeight; } + + /// Angle content, set if found in current context + double getAngle() const { return mfAngle; } + void setAngle(double fAngle = 0.0) { mfAngle = fAngle; mbOrientAuto = false; } + + /// OrientAuto content, set if found in current context + bool getOrientAuto() const { return mbOrientAuto; } + void setOrientAuto(bool bOrientAuto = true) { mbOrientAuto = bOrientAuto; } + + }; + } // end of namespace svgreader +} // end of namespace svgio + +////////////////////////////////////////////////////////////////////////////// + +#endif //INCLUDED_SVGIO_SVGREADER_SVGMARKERNODE_HXX + +// eof + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svgio/inc/svgio/svgreader/svgmasknode.hxx b/svgio/inc/svgio/svgreader/svgmasknode.hxx new file mode 100644 index 000000000000..a5914d7eb327 --- /dev/null +++ b/svgio/inc/svgio/svgreader/svgmasknode.hxx @@ -0,0 +1,98 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_SVGIO_SVGREADER_SVGMASKNODE_HXX +#define INCLUDED_SVGIO_SVGREADER_SVGMASKNODE_HXX + +#include <svgio/svgiodllapi.h> +#include <svgio/svgreader/svgnode.hxx> +#include <svgio/svgreader/svgstyleattributes.hxx> + +////////////////////////////////////////////////////////////////////////////// + +namespace svgio +{ + namespace svgreader + { + class SvgMaskNode : public SvgNode + { + private: + /// use styles + SvgStyleAttributes maSvgStyleAttributes; + + /// variable scan values, dependent of given XAttributeList + SvgNumber maX; + SvgNumber maY; + SvgNumber maWidth; + SvgNumber maHeight; + basegfx::B2DHomMatrix* mpaTransform; + SvgUnits maMaskUnits; + SvgUnits maMaskContentUnits; + + public: + SvgMaskNode( + SvgDocument& rDocument, + SvgNode* pParent); + virtual ~SvgMaskNode(); + + virtual const SvgStyleAttributes* getSvgStyleAttributes() const; + virtual void parseAttribute(const rtl::OUString& rTokenName, SVGToken aSVGToken, const rtl::OUString& aContent); + virtual void decomposeSvgNode(drawinglayer::primitive2d::Primitive2DSequence& rTarget, bool bReferenced) const; + + /// apply contained clipPath to given geometry + void apply(drawinglayer::primitive2d::Primitive2DSequence& rTarget) const; + + /// x content, set if found in current context + const SvgNumber& getX() const { return maX; } + void setX(const SvgNumber& rX = SvgNumber()) { maX = rX; } + + /// y content, set if found in current context + const SvgNumber& getY() const { return maY; } + void setY(const SvgNumber& rY = SvgNumber()) { maY = rY; } + + /// width content, set if found in current context + const SvgNumber& getWidth() const { return maWidth; } + void setWidth(const SvgNumber& rWidth = SvgNumber()) { maWidth = rWidth; } + + /// height content, set if found in current context + const SvgNumber& getHeight() const { return maHeight; } + void setHeight(const SvgNumber& rHeight = SvgNumber()) { maHeight = rHeight; } + + /// transform content + const basegfx::B2DHomMatrix* getTransform() const { return mpaTransform; } + void setTransform(const basegfx::B2DHomMatrix* pMatrix = 0) { if(mpaTransform) delete mpaTransform; mpaTransform = 0; if(pMatrix) mpaTransform = new basegfx::B2DHomMatrix(*pMatrix); } + + /// MaskUnits content + SvgUnits getMaskUnits() const { return maMaskUnits; } + void setMaskUnits(const SvgUnits aMaskUnits) { maMaskUnits = aMaskUnits; } + + /// MaskContentUnits content + SvgUnits getMaskContentUnits() const { return maMaskContentUnits; } + void setMaskContentUnits(const SvgUnits aMaskContentUnits) { maMaskContentUnits = aMaskContentUnits; } + }; + } // end of namespace svgreader +} // end of namespace svgio + +////////////////////////////////////////////////////////////////////////////// + +#endif //INCLUDED_SVGIO_SVGREADER_SVGMASKNODE_HXX + +// eof + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svgio/inc/svgio/svgreader/svgnode.hxx b/svgio/inc/svgio/svgreader/svgnode.hxx new file mode 100644 index 000000000000..5b3a2694dd18 --- /dev/null +++ b/svgio/inc/svgio/svgreader/svgnode.hxx @@ -0,0 +1,127 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_SVGIO_SVGREADER_SVGNODE_HXX +#define INCLUDED_SVGIO_SVGREADER_SVGNODE_HXX + +#include <svgio/svgiodllapi.h> +#include <svgio/svgreader/svgtools.hxx> +#include <svgio/svgreader/svgtoken.hxx> +#include <svgio/svgreader/svgpaint.hxx> +#include <basegfx/matrix/b2dhommatrix.hxx> +#include <com/sun/star/xml/sax/XAttributeList.hpp> +#include <vector> +#include <boost/unordered_map.hpp> + +////////////////////////////////////////////////////////////////////////////// +// predefines +namespace svgio +{ + namespace svgreader + { + class SvgNode; + class SvgDocument; + class SvgStyleAttributes; + } +} + +////////////////////////////////////////////////////////////////////////////// + +namespace svgio +{ + namespace svgreader + { + typedef ::std::vector< SvgNode* > SvgNodeVector; + + enum XmlSpace + { + XmlSpace_notset, + XmlSpace_default, + XmlSpace_preserve + }; + + class SvgNode : private boost::noncopyable, public InfoProvider + { + private: + /// basic data, Type, document we belong to and parent (if not root) + SVGToken maType; + SvgDocument& mrDocument; + const SvgNode* mpParent; + const SvgNode* mpAlternativeParent; + + /// sub hierarchy + SvgNodeVector maChildren; + + /// Id svan value + rtl::OUString* mpId; + + /// Class svan value + rtl::OUString* mpClass; + + /// XmlSpace value + XmlSpace maXmlSpace; + + public: + SvgNode( + SVGToken aType, + SvgDocument& rDocument, + SvgNode* pParent); + virtual ~SvgNode(); + + void parseAttributes(const com::sun::star::uno::Reference< com::sun::star::xml::sax::XAttributeList >& xAttribs); + virtual const SvgStyleAttributes* getSvgStyleAttributes() const; + virtual void parseAttribute(const rtl::OUString& rTokenName, SVGToken aSVGToken, const rtl::OUString& aContent); + virtual void decomposeSvgNode(drawinglayer::primitive2d::Primitive2DSequence& rTarget, bool bReferenced) const; + + /// basic data read access + SVGToken getType() const { return maType; } + const SvgDocument& getDocument() const { return mrDocument; } + const SvgNode* getParent() const { if(mpAlternativeParent) return mpAlternativeParent; return mpParent; } + const SvgNodeVector& getChildren() const { return maChildren; } + + /// InfoProvider support for %, em and ex values + virtual const basegfx::B2DRange* getCurrentViewPort() const; + virtual double getCurrentFontSize() const; + virtual double getCurrentXHeight() const; + + /// Id access + const rtl::OUString* getId() const { return mpId; } + void setId(const rtl::OUString* pfId = 0); + + /// Class access + const rtl::OUString* getClass() const { return mpClass; } + void setClass(const rtl::OUString* pfClass = 0); + + /// XmlSpace access + XmlSpace getXmlSpace() const; + void setXmlSpace(XmlSpace eXmlSpace = XmlSpace_notset) { maXmlSpace = eXmlSpace; } + + /// alternative parent + void setAlternativeParent(const SvgNode* pAlternativeParent = 0) { mpAlternativeParent = pAlternativeParent; } + }; + } // end of namespace svgreader +} // end of namespace svgio + +////////////////////////////////////////////////////////////////////////////// + +#endif //INCLUDED_SVGIO_SVGREADER_SVGNODE_HXX + +// eof + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svgio/inc/svgio/svgreader/svgpaint.hxx b/svgio/inc/svgio/svgreader/svgpaint.hxx new file mode 100644 index 000000000000..361125d107df --- /dev/null +++ b/svgio/inc/svgio/svgreader/svgpaint.hxx @@ -0,0 +1,65 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_SVGIO_SVGREADER_SVGPAINT_HXX +#define INCLUDED_SVGIO_SVGREADER_SVGPAINT_HXX + +#include <svgio/svgiodllapi.h> +#include <basegfx/color/bcolor.hxx> + +////////////////////////////////////////////////////////////////////////////// + +namespace svgio +{ + namespace svgreader + { + class SvgPaint + { + private: + basegfx::BColor maColor; + + /// bitfield + bool mbSet : 1; + bool mbOn : 1; + bool mbCurrent : 1; + + public: + SvgPaint(const basegfx::BColor& rColor = basegfx::BColor(0.0, 0.0, 0.0), bool bSet = false, bool bOn = false, bool bCurrent = false) + : maColor(rColor), + mbSet(bSet), + mbOn(bOn), + mbCurrent(bCurrent) + { + } + + const basegfx::BColor& getBColor() const { return maColor; } + bool isSet() const { return mbSet; } + bool isOn() const { return mbOn; } + bool isCurrent() const { return mbCurrent; } + }; + } // end of namespace svgreader +} // end of namespace svgio + +////////////////////////////////////////////////////////////////////////////// + +#endif //INCLUDED_SVGIO_SVGREADER_SVGPAINT_HXX + +// eof + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svgio/inc/svgio/svgreader/svgpathnode.hxx b/svgio/inc/svgio/svgreader/svgpathnode.hxx new file mode 100644 index 000000000000..a7506cee7f8e --- /dev/null +++ b/svgio/inc/svgio/svgreader/svgpathnode.hxx @@ -0,0 +1,75 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_SVGIO_SVGREADER_SVGPATHNODE_HXX +#define INCLUDED_SVGIO_SVGREADER_SVGPATHNODE_HXX + +#include <svgio/svgiodllapi.h> +#include <svgio/svgreader/svgnode.hxx> +#include <svgio/svgreader/svgstyleattributes.hxx> + +////////////////////////////////////////////////////////////////////////////// + +namespace svgio +{ + namespace svgreader + { + class SvgPathNode : public SvgNode + { + private: + /// use styles + SvgStyleAttributes maSvgStyleAttributes; + + /// variable scan values, dependent of given XAttributeList + basegfx::B2DPolyPolygon* mpPolyPolygon; + basegfx::B2DHomMatrix* mpaTransform; + SvgNumber maPathLength; + + public: + SvgPathNode( + SvgDocument& rDocument, + SvgNode* pParent); + virtual ~SvgPathNode(); + + virtual const SvgStyleAttributes* getSvgStyleAttributes() const; + virtual void parseAttribute(const rtl::OUString& rTokenName, SVGToken aSVGToken, const rtl::OUString& aContent); + virtual void decomposeSvgNode(drawinglayer::primitive2d::Primitive2DSequence& rTarget, bool bReferenced) const; + + /// path content, set if found in current context + const basegfx::B2DPolyPolygon* getPath() const { return mpPolyPolygon; } + void setPath(const basegfx::B2DPolyPolygon* pPath = 0) { if(mpPolyPolygon) delete mpPolyPolygon; mpPolyPolygon = 0; if(pPath) mpPolyPolygon = new basegfx::B2DPolyPolygon(*pPath); } + + /// transform content, set if found in current context + const basegfx::B2DHomMatrix* getTransform() const { return mpaTransform; } + void setTransform(const basegfx::B2DHomMatrix* pMatrix = 0) { if(mpaTransform) delete mpaTransform; mpaTransform = 0; if(pMatrix) mpaTransform = new basegfx::B2DHomMatrix(*pMatrix); } + + /// PathLength content + const SvgNumber& getPathLength() const { return maPathLength; } + void setPathLength(const SvgNumber& rPathLength = SvgNumber()) { maPathLength = rPathLength; } + }; + } // end of namespace svgreader +} // end of namespace svgio + +////////////////////////////////////////////////////////////////////////////// + +#endif //INCLUDED_SVGIO_SVGREADER_SVGPATHNODE_HXX + +// eof + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svgio/inc/svgio/svgreader/svgpatternnode.hxx b/svgio/inc/svgio/svgreader/svgpatternnode.hxx new file mode 100644 index 000000000000..946fdbfcb1a5 --- /dev/null +++ b/svgio/inc/svgio/svgreader/svgpatternnode.hxx @@ -0,0 +1,126 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_SVGIO_SVGREADER_SVGPATTERNNODE_HXX +#define INCLUDED_SVGIO_SVGREADER_SVGPATTERNNODE_HXX + +#include <svgio/svgiodllapi.h> +#include <svgio/svgreader/svgnode.hxx> +#include <svgio/svgreader/svgstyleattributes.hxx> + +////////////////////////////////////////////////////////////////////////////// + +namespace svgio +{ + namespace svgreader + { + class SvgPatternNode : public SvgNode + { + private: + /// buffered decomposition + drawinglayer::primitive2d::Primitive2DSequence aPrimitives; + + /// use styles + SvgStyleAttributes maSvgStyleAttributes; + + /// variable scan values, dependent of given XAttributeList + basegfx::B2DRange* mpViewBox; + SvgAspectRatio maSvgAspectRatio; + SvgNumber maX; + SvgNumber maY; + SvgNumber maWidth; + SvgNumber maHeight; + SvgUnits* mpPatternUnits; + SvgUnits* mpPatternContentUnits; + basegfx::B2DHomMatrix* mpaPatternTransform; + + /// link to another pattern used as style. If maXLink + /// is set, the node can be fetched on demand by using + // tryToFindLink (buffered) + rtl::OUString maXLink; + const SvgPatternNode* mpXLink; + + /// link on demand + void tryToFindLink(); + + public: + SvgPatternNode( + SvgDocument& rDocument, + SvgNode* pParent); + virtual ~SvgPatternNode(); + + virtual const SvgStyleAttributes* getSvgStyleAttributes() const; + virtual void parseAttribute(const rtl::OUString& rTokenName, SVGToken aSVGToken, const rtl::OUString& aContent); + + /// global helpers + void getValuesRelative(double& rfX, double& rfY, double& rfW, double& rfH, const basegfx::B2DRange& rGeoRange, SvgNode& rUser) const; + + /// get pattern primitives buffered, uses decomposeSvgNode internally + const drawinglayer::primitive2d::Primitive2DSequence& getPatternPrimitives() const; + + /// InfoProvider support for % values + virtual const basegfx::B2DRange* getCurrentViewPort() const; + + /// viewBox content + const basegfx::B2DRange* getViewBox() const; + void setViewBox(const basegfx::B2DRange* pViewBox = 0) { if(mpViewBox) delete mpViewBox; mpViewBox = 0; if(pViewBox) mpViewBox = new basegfx::B2DRange(*pViewBox); } + + /// SvgAspectRatio content + const SvgAspectRatio& getSvgAspectRatio() const; + void setSvgAspectRatio(const SvgAspectRatio& rSvgAspectRatio = SvgAspectRatio()) { maSvgAspectRatio = rSvgAspectRatio; } + + /// X content, set if found in current context + const SvgNumber& getX() const; + void setX(const SvgNumber& rX = SvgNumber()) { maX = rX; } + + /// Y content, set if found in current context + const SvgNumber& getY() const; + void setY(const SvgNumber& rY = SvgNumber()) { maY = rY; } + + /// Width content, set if found in current context + const SvgNumber& getWidth() const; + void setWidth(const SvgNumber& rWidth = SvgNumber()) { maWidth = rWidth; } + + /// Height content, set if found in current context + const SvgNumber& getHeight() const; + void setHeight(const SvgNumber& rHeight = SvgNumber()) { maHeight = rHeight; } + + /// PatternUnits content + const SvgUnits* getPatternUnits() const; + void setPatternUnits(const SvgUnits aPatternUnits) { if(mpPatternUnits) delete mpPatternUnits; mpPatternUnits = 0; mpPatternUnits = new SvgUnits(aPatternUnits); } + + /// PatternContentUnits content + const SvgUnits* getPatternContentUnits() const; + void setPatternContentUnits(const SvgUnits aPatternContentUnits) { if(mpPatternContentUnits) delete mpPatternContentUnits; mpPatternContentUnits = 0; mpPatternContentUnits = new SvgUnits(aPatternContentUnits); } + + /// PatternTransform content + const basegfx::B2DHomMatrix* getPatternTransform() const; + void setPatternTransform(const basegfx::B2DHomMatrix* pMatrix = 0) { if(mpaPatternTransform) delete mpaPatternTransform; mpaPatternTransform = 0; if(pMatrix) mpaPatternTransform = new basegfx::B2DHomMatrix(*pMatrix); } + + }; + } // end of namespace svgreader +} // end of namespace svgio + +////////////////////////////////////////////////////////////////////////////// + +#endif //INCLUDED_SVGIO_SVGREADER_SVGPATTERNNODE_HXX + +// eof + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svgio/inc/svgio/svgreader/svgpolynode.hxx b/svgio/inc/svgio/svgreader/svgpolynode.hxx new file mode 100644 index 000000000000..5ebd8076bb58 --- /dev/null +++ b/svgio/inc/svgio/svgreader/svgpolynode.hxx @@ -0,0 +1,78 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_SVGIO_SVGREADER_SVGPOLYNODE_HXX +#define INCLUDED_SVGIO_SVGREADER_SVGPOLYNODE_HXX + +#include <svgio/svgiodllapi.h> +#include <svgio/svgreader/svgnode.hxx> +#include <svgio/svgreader/svgstyleattributes.hxx> +#include <basegfx/polygon/b2dpolygon.hxx> + +////////////////////////////////////////////////////////////////////////////// + +namespace svgio +{ + namespace svgreader + { + class SvgPolyNode : public SvgNode + { + private: + /// use styles + SvgStyleAttributes maSvgStyleAttributes; + + /// variable scan values, dependent of given XAttributeList + basegfx::B2DPolygon* mpPolygon; + basegfx::B2DHomMatrix* mpaTransform; + + /// bitfield + bool mbIsPolyline : 1; // true = polyline, false = polygon + + public: + SvgPolyNode( + SvgDocument& rDocument, + SvgNode* pParent, + bool bIsPolyline); + virtual ~SvgPolyNode(); + + virtual const SvgStyleAttributes* getSvgStyleAttributes() const; + virtual void parseAttribute(const rtl::OUString& rTokenName, SVGToken aSVGToken, const rtl::OUString& aContent); + virtual void decomposeSvgNode(drawinglayer::primitive2d::Primitive2DSequence& rTarget, bool bReferenced) const; + + /// type read access + bool isPolyline() const { return mbIsPolyline; } + + /// Polygon content, set if found in current context + const basegfx::B2DPolygon* getPolygon() const { return mpPolygon; } + void setPolygon(const basegfx::B2DPolygon* pPolygon = 0) { if(mpPolygon) delete mpPolygon; mpPolygon = 0; if(pPolygon) mpPolygon = new basegfx::B2DPolygon(*pPolygon); } + + /// transform content, set if found in current context + const basegfx::B2DHomMatrix* getTransform() const { return mpaTransform; } + void setTransform(const basegfx::B2DHomMatrix* pMatrix = 0) { if(mpaTransform) delete mpaTransform; mpaTransform = 0; if(pMatrix) mpaTransform = new basegfx::B2DHomMatrix(*pMatrix); } + }; + } // end of namespace svgreader +} // end of namespace svgio + +////////////////////////////////////////////////////////////////////////////// + +#endif //INCLUDED_SVGIO_SVGREADER_SVGPOLYNODE_HXX + +// eof + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svgio/inc/svgio/svgreader/svgrectnode.hxx b/svgio/inc/svgio/svgreader/svgrectnode.hxx new file mode 100644 index 000000000000..f6e10eac2e98 --- /dev/null +++ b/svgio/inc/svgio/svgreader/svgrectnode.hxx @@ -0,0 +1,95 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_SVGIO_SVGREADER_SVGRECTNODE_HXX +#define INCLUDED_SVGIO_SVGREADER_SVGRECTNODE_HXX + +#include <svgio/svgiodllapi.h> +#include <svgio/svgreader/svgnode.hxx> +#include <svgio/svgreader/svgstyleattributes.hxx> + +////////////////////////////////////////////////////////////////////////////// + +namespace svgio +{ + namespace svgreader + { + class SvgRectNode : public SvgNode + { + private: + /// use styles + SvgStyleAttributes maSvgStyleAttributes; + + /// variable scan values, dependent of given XAttributeList + SvgNumber maX; + SvgNumber maY; + SvgNumber maWidth; + SvgNumber maHeight; + SvgNumber maRx; + SvgNumber maRy; + basegfx::B2DHomMatrix* mpaTransform; + + public: + SvgRectNode( + SvgDocument& rDocument, + SvgNode* pParent); + virtual ~SvgRectNode(); + + virtual const SvgStyleAttributes* getSvgStyleAttributes() const; + virtual void parseAttribute(const rtl::OUString& rTokenName, SVGToken aSVGToken, const rtl::OUString& aContent); + virtual void decomposeSvgNode(drawinglayer::primitive2d::Primitive2DSequence& rTarget, bool bReferenced) const; + + /// x content, set if found in current context + const SvgNumber& getX() const { return maX; } + void setX(const SvgNumber& rX = SvgNumber()) { maX = rX; } + + /// y content, set if found in current context + const SvgNumber& getY() const { return maY; } + void setY(const SvgNumber& rY = SvgNumber()) { maY = rY; } + + /// width content, set if found in current context + const SvgNumber& getWidth() const { return maWidth; } + void setWidth(const SvgNumber& rWidth = SvgNumber()) { maWidth = rWidth; } + + /// height content, set if found in current context + const SvgNumber& getHeight() const { return maHeight; } + void setHeight(const SvgNumber& rHeight = SvgNumber()) { maHeight = rHeight; } + + /// Rx content, set if found in current context + const SvgNumber& getRx() const { return maRx; } + void setRx(const SvgNumber& rRx = SvgNumber()) { maRx = rRx; } + + /// Ry content, set if found in current context + const SvgNumber& getRy() const { return maRy; } + void setRy(const SvgNumber& rRy = SvgNumber()) { maRy = rRy; } + + /// transform content, set if found in current context + const basegfx::B2DHomMatrix* getTransform() const { return mpaTransform; } + void setTransform(const basegfx::B2DHomMatrix* pMatrix = 0) { if(mpaTransform) delete mpaTransform; mpaTransform = 0; if(pMatrix) mpaTransform = new basegfx::B2DHomMatrix(*pMatrix); } + }; + } // end of namespace svgreader +} // end of namespace svgio + +////////////////////////////////////////////////////////////////////////////// + +#endif //INCLUDED_SVGIO_SVGREADER_SVGRECTNODE_HXX + +// eof + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svgio/inc/svgio/svgreader/svgstyleattributes.hxx b/svgio/inc/svgio/svgreader/svgstyleattributes.hxx new file mode 100644 index 000000000000..66789586ad6b --- /dev/null +++ b/svgio/inc/svgio/svgreader/svgstyleattributes.hxx @@ -0,0 +1,411 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_SVGIO_SVGREADER_SVGSTYLEATTRIBUTES_HXX +#define INCLUDED_SVGIO_SVGREADER_SVGSTYLEATTRIBUTES_HXX + +#include <svgio/svgiodllapi.h> +#include <svgio/svgreader/svgpaint.hxx> +#include <svgio/svgreader/svgnode.hxx> +#include <vcl/vclenum.hxx> + +////////////////////////////////////////////////////////////////////////////// +// predefines + +namespace svgio { namespace svgreader { + class SvgGradientNode; + class SvgPatternNode; + class SvgMarkerNode; +}} + +////////////////////////////////////////////////////////////////////////////// + +namespace svgio +{ + namespace svgreader + { + enum StrokeLinecap + { + StrokeLinecap_notset, + StrokeLinecap_butt, + StrokeLinecap_round, + StrokeLinecap_square + }; + + enum StrokeLinejoin + { + StrokeLinejoin_notset, + StrokeLinejoin_miter, + StrokeLinejoin_round, + StrokeLinejoin_bevel + }; + + enum FontStretch + { + FontStretch_notset, + FontStretch_normal, + FontStretch_wider, + FontStretch_narrower, + FontStretch_ultra_condensed, + FontStretch_extra_condensed, + FontStretch_condensed, + FontStretch_semi_condensed, + FontStretch_semi_expanded, + FontStretch_expanded, + FontStretch_extra_expanded, + FontStretch_ultra_expanded + }; + + FontStretch getWider(FontStretch aSource); + FontStretch getNarrower(FontStretch aSource); + + enum FontStyle + { + FontStyle_notset, + FontStyle_normal, + FontStyle_italic, + FontStyle_oblique + }; + + enum FontVariant + { + FontVariant_notset, + FontVariant_normal, + FontVariant_small_caps + }; + + enum FontWeight + { + FontWeight_notset, + FontWeight_100, + FontWeight_200, + FontWeight_300, + FontWeight_400, // same as FontWeight_normal + FontWeight_500, + FontWeight_600, + FontWeight_700, // same as FontWeight_bold + FontWeight_800, + FontWeight_900, + FontWeight_bolder, + FontWeight_lighter, + }; + + FontWeight getBolder(FontWeight aSource); + FontWeight getLighter(FontWeight aSource); + ::FontWeight getVclFontWeight(FontWeight aSource); + + enum TextAlign + { + TextAlign_notset, + TextAlign_left, + TextAlign_right, + TextAlign_center, + TextAlign_justify + }; + + enum TextDecoration + { + TextDecoration_notset, + TextDecoration_none, + TextDecoration_underline, + TextDecoration_overline, + TextDecoration_line_through, + TextDecoration_blink + }; + + enum TextAnchor + { + TextAnchor_notset, + TextAnchor_start, + TextAnchor_middle, + TextAnchor_end + }; + + class SvgStyleAttributes + { + private: + SvgNode& mrOwner; + const SvgStyleAttributes* mpCssStyleParent; + + SvgPaint maFill; + SvgPaint maStroke; + SvgPaint maStopColor; + SvgNumber maStrokeWidth; + SvgNumber maStopOpacity; + const SvgGradientNode* mpSvgGradientNodeFill; + const SvgGradientNode* mpSvgGradientNodeStroke; + const SvgPatternNode* mpSvgPatternNodeFill; + const SvgPatternNode* mpSvgPatternNodeStroke; + SvgNumber maFillOpacity; + SvgNumberVector maStrokeDasharray; + SvgNumber maStrokeDashOffset; + StrokeLinecap maStrokeLinecap; + StrokeLinejoin maStrokeLinejoin; + SvgNumber maStrokeMiterLimit; + SvgNumber maStrokeOpacity; + SvgStringVector maFontFamily; + SvgNumber maFontSize; + FontStretch maFontStretch; + FontStyle maFontStyle; + FontVariant maFontVariant; + FontWeight maFontWeight; + TextAlign maTextAlign; + TextDecoration maTextDecoration; + TextAnchor maTextAnchor; + SvgPaint maColor; + SvgNumber maOpacity; + + /// link to content. If set, the node can be fetched on demand + rtl::OUString maClipPathXLink; + rtl::OUString maMaskXLink; + + /// link to markers. If set, the node can be fetched on demand + rtl::OUString maMarkerStartXLink; + const SvgMarkerNode* mpMarkerStartXLink; + rtl::OUString maMarkerMidXLink; + const SvgMarkerNode* mpMarkerMidXLink; + rtl::OUString maMarkerEndXLink; + const SvgMarkerNode* mpMarkerEndXLink; + + /// bitfield + bool maFillRule : 1; // true: NonZero, false: EvenOdd + bool maFillRuleSet : 1; + + // defines if this attributes are part of a ClipPath. If yes, + // rough geometry will be created on decomposition by patching + // vaules for fill, stroke, strokeWidth and others + bool mbIsClipPathContent : 1; + + // ClipRule setting (only valid wne mbIsClipPathContent == true) + bool mbClipRule : 1; // true == nonzero(default), false == evenodd + + /// internal helpers + void add_fillGradient( + const basegfx::B2DPolyPolygon& rPath, + drawinglayer::primitive2d::Primitive2DSequence& rTarget, + const SvgGradientNode& rFillGradient, + const basegfx::B2DRange& rGeoRange) const; + void add_fillPatternTransform( + const basegfx::B2DPolyPolygon& rPath, + drawinglayer::primitive2d::Primitive2DSequence& rTarget, + const SvgPatternNode& rFillGradient, + const basegfx::B2DRange& rGeoRange) const; + void add_fillPattern( + const basegfx::B2DPolyPolygon& rPath, + drawinglayer::primitive2d::Primitive2DSequence& rTarget, + const SvgPatternNode& rFillGradient, + const basegfx::B2DRange& rGeoRange) const; + void add_fill( + const basegfx::B2DPolyPolygon& rPath, + drawinglayer::primitive2d::Primitive2DSequence& rTarget, + const basegfx::B2DRange& rGeoRange) const; + void add_stroke( + const basegfx::B2DPolyPolygon& rPath, + drawinglayer::primitive2d::Primitive2DSequence& rTarget, + const basegfx::B2DRange& rGeoRange) const; + bool prepare_singleMarker( + drawinglayer::primitive2d::Primitive2DSequence& rMarkerPrimitives, + basegfx::B2DHomMatrix& rMarkerTransform, + basegfx::B2DRange& rClipRange, + const SvgMarkerNode& rMarker) const; + void add_singleMarker( + drawinglayer::primitive2d::Primitive2DSequence& rTarget, + const drawinglayer::primitive2d::Primitive2DSequence& rMarkerPrimitives, + const basegfx::B2DHomMatrix& rMarkerTransform, + const basegfx::B2DRange& rClipRange, + const SvgMarkerNode& rMarker, + const basegfx::B2DPolygon& rCandidate, + const sal_uInt32 nIndex) const; + void add_markers( + const basegfx::B2DPolyPolygon& rPath, + drawinglayer::primitive2d::Primitive2DSequence& rTarget) const; + + public: + /// local attribute scanner + void parseStyleAttribute(const rtl::OUString& rTokenName, SVGToken aSVGToken, const rtl::OUString& aContent); + + /// helper which does the necessary with a given path + void add_text( + drawinglayer::primitive2d::Primitive2DSequence& rTarget, + drawinglayer::primitive2d::Primitive2DSequence& rSource) const; + void add_path( + const basegfx::B2DPolyPolygon& rPath, + drawinglayer::primitive2d::Primitive2DSequence& rTarget) const; + void add_postProcess( + drawinglayer::primitive2d::Primitive2DSequence& rTarget, + const drawinglayer::primitive2d::Primitive2DSequence& rSource, + const basegfx::B2DHomMatrix* pTransform) const; + + /// helper to evtl. link to css style + void checkForCssStyle(const rtl::OUString& rClassStr) const; + + /// scan helpers + void readStyle(const rtl::OUString& rCandidate); + const SvgStyleAttributes* getParentStyle() const; + + SvgStyleAttributes(SvgNode& rOwner); + ~SvgStyleAttributes(); + + /// fill content + const basegfx::BColor* getFill() const; + void setFill(const SvgPaint& rFill) { maFill = rFill; } + + /// stroke content + const basegfx::BColor* getStroke() const; + void setStroke(const SvgPaint& rStroke) { maStroke = rStroke; } + + /// stop color content + const basegfx::BColor& getStopColor() const; + void setStopColor(const SvgPaint& rStopColor) { maStopColor = rStopColor; } + + /// stroke-width content + const SvgNumber getStrokeWidth() const; + void setStrokeWidth(const SvgNumber& rStrokeWidth = SvgNumber()) { maStrokeWidth = rStrokeWidth; } + + /// stop opacity content + const SvgNumber getStopOpacity() const; + void setStopOpacity(const SvgNumber& rStopOpacity = SvgNumber()) { maStopOpacity = rStopOpacity; } + + /// access to evtl. set fill gradient + const SvgGradientNode* getSvgGradientNodeFill() const; + void setSvgGradientNodeFill(const SvgGradientNode* pNew) { mpSvgGradientNodeFill = pNew; } + + /// access to evtl. set fill pattern + const SvgPatternNode* getSvgPatternNodeFill() const; + void setSvgPatternNodeFill(const SvgPatternNode* pNew) { mpSvgPatternNodeFill = pNew; } + + /// access to evtl. set stroke gradient + const SvgGradientNode* getSvgGradientNodeStroke() const; + void setSvgGradientNodeStroke(const SvgGradientNode* pNew) { mpSvgGradientNodeStroke = pNew; } + + /// access to evtl. set stroke pattern + const SvgPatternNode* getSvgPatternNodeStroke() const; + void setSvgPatternNodeStroke(const SvgPatternNode* pNew) { mpSvgPatternNodeStroke = pNew; } + + /// fill opacity content + const SvgNumber getFillOpacity() const; + void setFillOpacity(const SvgNumber& rFillOpacity = SvgNumber()) { maFillOpacity = rFillOpacity; } + + /// fill rule content + bool getFillRule() const; + void setFillRule(const bool* pFillRule = 0); + + /// fill StrokeDasharray content + const SvgNumberVector& getStrokeDasharray() const; + void setStrokeDasharray(const SvgNumberVector& rStrokeDasharray = SvgNumberVector()) { maStrokeDasharray = rStrokeDasharray; } + + /// StrokeDashOffset content + const SvgNumber getStrokeDashOffset() const; + void setStrokeDashOffset(const SvgNumber& rStrokeDashOffset = SvgNumber()) { maStrokeDashOffset = rStrokeDashOffset; } + + /// StrokeLinecap content + StrokeLinecap getStrokeLinecap() const; + void setStrokeLinecap(const StrokeLinecap aStrokeLinecap = StrokeLinecap_notset) { maStrokeLinecap = aStrokeLinecap; } + + /// StrokeLinejoin content + StrokeLinejoin getStrokeLinejoin() const; + void setStrokeLinejoin(const StrokeLinejoin aStrokeLinejoin = StrokeLinejoin_notset) { maStrokeLinejoin = aStrokeLinejoin; } + + /// StrokeMiterLimit content + const SvgNumber getStrokeMiterLimit() const; + void setStrokeMiterLimit(const SvgNumber& rStrokeMiterLimit = SvgNumber()) { maStrokeMiterLimit = rStrokeMiterLimit; } + + /// StrokeOpacity content + const SvgNumber getStrokeOpacity() const; + void setStrokeOpacity(const SvgNumber& rStrokeOpacity = SvgNumber()) { maStrokeOpacity = rStrokeOpacity; } + + /// Font content + const SvgStringVector& getFontFamily() const; + void setFontFamily(const SvgStringVector& rSvgStringVector = SvgStringVector()) { maFontFamily = rSvgStringVector; } + + /// FontSize content + const SvgNumber getFontSize() const; + void setFontSize(const SvgNumber& rFontSize = SvgNumber()) { maFontSize = rFontSize; } + + /// FontStretch content + FontStretch getFontStretch() const; + void setFontStretch(const FontStretch aFontStretch = FontStretch_notset) { maFontStretch = aFontStretch; } + + /// FontStyle content + FontStyle getFontStyle() const; + void setFontStyle(const FontStyle aFontStyle = FontStyle_notset) { maFontStyle = aFontStyle; } + + /// FontVariant content + FontVariant getFontVariant() const; + void setFontVariant(const FontVariant aFontVariant = FontVariant_notset) { maFontVariant = aFontVariant; } + + /// FontWeight content + FontWeight getFontWeight() const; + void setFontWeight(const FontWeight aFontWeight = FontWeight_notset) { maFontWeight = aFontWeight; } + + /// TextAlign content + TextAlign getTextAlign() const; + void setTextAlign(const TextAlign aTextAlign = TextAlign_notset) { maTextAlign = aTextAlign; } + + /// TextDecoration content + const SvgStyleAttributes* getTextDecorationDefiningSvgStyleAttributes() const; + TextDecoration getTextDecoration() const; + void setTextDecoration(const TextDecoration aTextDecoration = TextDecoration_notset) { maTextDecoration = aTextDecoration; } + + /// TextAnchor content + TextAnchor getTextAnchor() const; + void setTextAnchor(const TextAnchor aTextAnchor = TextAnchor_notset) { maTextAnchor = aTextAnchor; } + + /// Color content + const basegfx::BColor* getColor() const; + void setColor(const SvgPaint& rColor) { maColor = rColor; } + + /// Opacity content + const SvgNumber getOpacity() const { return maOpacity; } + void setOpacity(const SvgNumber& rOpacity = SvgNumber()) { maOpacity = rOpacity; } + + // ClipPathXLink content + const rtl::OUString getClipPathXLink() const { return maClipPathXLink; } + void setClipPathXLink(const rtl::OUString& rNew) { maClipPathXLink = rNew; } + + // MaskXLink content + const rtl::OUString getMaskXLink() const { return maMaskXLink; } + void setMaskXLink(const rtl::OUString& rNew) { maMaskXLink = rNew; } + + // MarkerStartXLink content + const rtl::OUString getMarkerStartXLink() const; + const SvgMarkerNode* accessMarkerStartXLink() const; + void setMarkerStartXLink(const rtl::OUString& rNew) { maMarkerStartXLink = rNew; } + + // MarkerMidXLink content + const rtl::OUString getMarkerMidXLink() const; + const SvgMarkerNode* accessMarkerMidXLink() const; + void setMarkerMidXLink(const rtl::OUString& rNew) { maMarkerMidXLink = rNew; } + + // MarkerEndXLink content + const rtl::OUString getMarkerEndXLink() const; + const SvgMarkerNode* accessMarkerEndXLink() const; + void setMarkerEndXLink(const rtl::OUString& rNew) { maMarkerEndXLink = rNew; } + + }; + } // end of namespace svgreader +} // end of namespace svgio + +////////////////////////////////////////////////////////////////////////////// + +#endif //INCLUDED_SVGIO_SVGREADER_SVGSTYLEATTRIBUTES_HXX + +// eof + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svgio/inc/svgio/svgreader/svgstylenode.hxx b/svgio/inc/svgio/svgreader/svgstylenode.hxx new file mode 100644 index 000000000000..37a7ef7d8eb3 --- /dev/null +++ b/svgio/inc/svgio/svgreader/svgstylenode.hxx @@ -0,0 +1,64 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_SVGIO_SVGREADER_SVGSTYLENODE_HXX +#define INCLUDED_SVGIO_SVGREADER_SVGSTYLENODE_HXX + +#include <svgio/svgiodllapi.h> +#include <svgio/svgreader/svgnode.hxx> +#include <svgio/svgreader/svgstyleattributes.hxx> + +////////////////////////////////////////////////////////////////////////////// + +namespace svgio +{ + namespace svgreader + { + class SvgStyleNode : public SvgNode + { + private: + /// use styles + std::vector< SvgStyleAttributes* > maSvgStyleAttributes; + + /// bitfield + bool mbTextCss : 1; // true == type is 'text/css' + + public: + SvgStyleNode( + SvgDocument& rDocument, + SvgNode* pParent); + virtual ~SvgStyleNode(); + + virtual void parseAttribute(const rtl::OUString& rTokenName, SVGToken aSVGToken, const rtl::OUString& aContent); + void addCssStyleSheet(const rtl::OUString& aContent); + + /// textCss access + bool isTextCss() const { return mbTextCss; } + void setTextCss(bool bNew) { mbTextCss = bNew; } + }; + } // end of namespace svgreader +} // end of namespace svgio + +////////////////////////////////////////////////////////////////////////////// + +#endif //INCLUDED_SVGIO_SVGREADER_SVGSTYLENODE_HXX + +// eof + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svgio/inc/svgio/svgreader/svgsvgnode.hxx b/svgio/inc/svgio/svgreader/svgsvgnode.hxx new file mode 100644 index 000000000000..0da68741b636 --- /dev/null +++ b/svgio/inc/svgio/svgreader/svgsvgnode.hxx @@ -0,0 +1,97 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_SVGIO_SVGREADER_SVGSVGNODE_HXX +#define INCLUDED_SVGIO_SVGREADER_SVGSVGNODE_HXX + +#include <svgio/svgiodllapi.h> +#include <svgio/svgreader/svgstyleattributes.hxx> + +////////////////////////////////////////////////////////////////////////////// + +namespace svgio +{ + namespace svgreader + { + class SvgSvgNode : public SvgNode + { + private: + /// use styles + SvgStyleAttributes maSvgStyleAttributes; + + /// variable scan values, dependent of given XAttributeList + basegfx::B2DRange* mpViewBox; + SvgAspectRatio maSvgAspectRatio; + SvgNumber maX; + SvgNumber maY; + SvgNumber maWidth; + SvgNumber maHeight; + SvgNumber maVersion; + + public: + SvgSvgNode( + SvgDocument& rDocument, + SvgNode* pParent); + virtual ~SvgSvgNode(); + + virtual const SvgStyleAttributes* getSvgStyleAttributes() const; + virtual void parseAttribute(const rtl::OUString& rTokenName, SVGToken aSVGToken, const rtl::OUString& aContent); + virtual void decomposeSvgNode(drawinglayer::primitive2d::Primitive2DSequence& rTarget, bool bReferenced) const; + + /// InfoProvider support for % values + virtual const basegfx::B2DRange* getCurrentViewPort() const; + + /// viewBox content + const basegfx::B2DRange* getViewBox() const { return mpViewBox; } + void setViewBox(const basegfx::B2DRange* pViewBox = 0) { if(mpViewBox) delete mpViewBox; mpViewBox = 0; if(pViewBox) mpViewBox = new basegfx::B2DRange(*pViewBox); } + + /// SvgAspectRatio content + const SvgAspectRatio& getSvgAspectRatio() const { return maSvgAspectRatio; } + void setSvgAspectRatio(const SvgAspectRatio& rSvgAspectRatio = SvgAspectRatio()) { maSvgAspectRatio = rSvgAspectRatio; } + + /// x content + const SvgNumber& getX() const { return maX; } + void setX(const SvgNumber& rX = SvgNumber()) { maX = rX; } + + /// y content + const SvgNumber& getY() const { return maY; } + void setY(const SvgNumber& rY = SvgNumber()) { maY = rY; } + + /// width content + const SvgNumber& getWidth() const { return maWidth; } + void setWidth(const SvgNumber& rWidth = SvgNumber()) { maWidth = rWidth; } + + /// height content + const SvgNumber& getHeight() const { return maHeight; } + void setHeight(const SvgNumber& rHeight = SvgNumber()) { maHeight = rHeight; } + + /// version content + const SvgNumber& getVersion() const { return maVersion; } + void setVersion(const SvgNumber& rVersion = SvgNumber()) { maVersion = rVersion; } + }; + } // end of namespace svgreader +} // end of namespace svgio + +////////////////////////////////////////////////////////////////////////////// + +#endif //INCLUDED_SVGIO_SVGREADER_SVGSVGNODE_HXX + +// eof + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svgio/inc/svgio/svgreader/svgsymbolnode.hxx b/svgio/inc/svgio/svgreader/svgsymbolnode.hxx new file mode 100644 index 000000000000..b4fd0428c7d3 --- /dev/null +++ b/svgio/inc/svgio/svgreader/svgsymbolnode.hxx @@ -0,0 +1,68 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_SVGIO_SVGREADER_SVGSYMBOLNODE_HXX +#define INCLUDED_SVGIO_SVGREADER_SVGSYMBOLNODE_HXX + +#include <svgio/svgiodllapi.h> +#include <svgio/svgreader/svgstyleattributes.hxx> + +////////////////////////////////////////////////////////////////////////////// + +namespace svgio +{ + namespace svgreader + { + class SvgSymbolNode : public SvgNode + { + private: + /// use styles + SvgStyleAttributes maSvgStyleAttributes; + + /// variable scan values, dependent of given XAttributeList + basegfx::B2DRange* mpViewBox; + SvgAspectRatio maSvgAspectRatio; + + public: + SvgSymbolNode( + SvgDocument& rDocument, + SvgNode* pParent); + virtual ~SvgSymbolNode(); + + virtual const SvgStyleAttributes* getSvgStyleAttributes() const; + virtual void parseAttribute(const rtl::OUString& rTokenName, SVGToken aSVGToken, const rtl::OUString& aContent); + + /// viewBox content + const basegfx::B2DRange* getViewBox() const { return mpViewBox; } + void setViewBox(const basegfx::B2DRange* pViewBox = 0) { if(mpViewBox) delete mpViewBox; mpViewBox = 0; if(pViewBox) mpViewBox = new basegfx::B2DRange(*pViewBox); } + + /// SvgAspectRatio content + const SvgAspectRatio& getSvgAspectRatio() const { return maSvgAspectRatio; } + void setSvgAspectRatio(const SvgAspectRatio& rSvgAspectRatio = SvgAspectRatio()) { maSvgAspectRatio = rSvgAspectRatio; } + }; + } // end of namespace svgreader +} // end of namespace svgio + +////////////////////////////////////////////////////////////////////////////// + +#endif //INCLUDED_SVGIO_SVGREADER_SVGSYMBOLNODE_HXX + +// eof + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svgio/inc/svgio/svgreader/svgtextnode.hxx b/svgio/inc/svgio/svgreader/svgtextnode.hxx new file mode 100644 index 000000000000..59ff27eac756 --- /dev/null +++ b/svgio/inc/svgio/svgreader/svgtextnode.hxx @@ -0,0 +1,80 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_SVGIO_SVGREADER_SVGTEXTNODE_HXX +#define INCLUDED_SVGIO_SVGREADER_SVGTEXTNODE_HXX + +#include <svgio/svgiodllapi.h> +#include <svgio/svgreader/svgnode.hxx> +#include <svgio/svgreader/svgstyleattributes.hxx> +#include <svgio/svgreader/svgcharacternode.hxx> + +////////////////////////////////////////////////////////////////////////////// + +namespace svgio +{ + namespace svgreader + { + class SvgTextNode : public SvgNode + { + private: + /// use styles + SvgStyleAttributes maSvgStyleAttributes; + + /// variable scan values, dependent of given XAttributeList + basegfx::B2DHomMatrix* mpaTransform; + SvgTextPositions maSvgTextPositions; + + /// local helpers + void DecomposeChild( + const SvgNode& rCandidate, + drawinglayer::primitive2d::Primitive2DSequence& rTarget, + SvgTextPosition& rSvgTextPosition) const; + void addTextPrimitives( + const SvgNode& rCandidate, + drawinglayer::primitive2d::Primitive2DSequence& rTarget, + drawinglayer::primitive2d::Primitive2DSequence& rSource) const; + + public: + SvgTextNode( + SvgDocument& rDocument, + SvgNode* pParent); + virtual ~SvgTextNode(); + + virtual const SvgStyleAttributes* getSvgStyleAttributes() const; + virtual void parseAttribute(const rtl::OUString& rTokenName, SVGToken aSVGToken, const rtl::OUString& aContent); + virtual void decomposeSvgNode(drawinglayer::primitive2d::Primitive2DSequence& rTarget, bool bReferenced) const; + + /// transform content, set if found in current context + const basegfx::B2DHomMatrix* getTransform() const { return mpaTransform; } + void setTransform(const basegfx::B2DHomMatrix* pMatrix = 0) { if(mpaTransform) delete mpaTransform; mpaTransform = 0; if(pMatrix) mpaTransform = new basegfx::B2DHomMatrix(*pMatrix); } + + /// access to SvgTextPositions + const SvgTextPositions& getSvgTextPositions() const { return maSvgTextPositions; } + }; + } // end of namespace svgreader +} // end of namespace svgio + +////////////////////////////////////////////////////////////////////////////// + +#endif //INCLUDED_SVGIO_SVGREADER_SVGTEXTNODE_HXX + +// eof + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svgio/inc/svgio/svgreader/svgtextpathnode.hxx b/svgio/inc/svgio/svgreader/svgtextpathnode.hxx new file mode 100644 index 000000000000..8c9a1d13281f --- /dev/null +++ b/svgio/inc/svgio/svgreader/svgtextpathnode.hxx @@ -0,0 +1,86 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_SVGIO_SVGREADER_SVGTEXTPATHNODE_HXX +#define INCLUDED_SVGIO_SVGREADER_SVGTEXTPATHNODE_HXX + +#include <svgio/svgiodllapi.h> +#include <svgio/svgreader/svgnode.hxx> +#include <svgio/svgreader/svgstyleattributes.hxx> +#include <svgio/svgreader/svgpathnode.hxx> + +////////////////////////////////////////////////////////////////////////////// + +namespace svgio +{ + namespace svgreader + { + class SvgTextPathNode : public SvgNode + { + private: + /// use styles + SvgStyleAttributes maSvgStyleAttributes; + + /// link to path content. If maXLink + /// is set, the node can be fetched on demand + rtl::OUString maXLink; + + /// variable scan values, dependent of given XAttributeList + SvgNumber maStartOffset; + + /// bitfield + bool mbMethod : 1; // true = align, false = stretch + bool mbSpacing : 1; // true = auto, false = exact + + public: + SvgTextPathNode( + SvgDocument& rDocument, + SvgNode* pParent); + virtual ~SvgTextPathNode(); + + virtual const SvgStyleAttributes* getSvgStyleAttributes() const; + virtual void parseAttribute(const rtl::OUString& rTokenName, SVGToken aSVGToken, const rtl::OUString& aContent); + void decomposePathNode( + const drawinglayer::primitive2d::Primitive2DSequence& rPathContent, + drawinglayer::primitive2d::Primitive2DSequence& rTarget, + const basegfx::B2DPoint& rTextStart) const; + bool isValid() const; + + /// StartOffset content + const SvgNumber& getStartOffset() const { return maStartOffset; } + void setStartOffset(const SvgNumber& rStartOffset = SvgNumber()) { maStartOffset = rStartOffset; } + + /// Method content + bool getMethod() const { return mbMethod; } + void setMethod(bool bNew) { mbMethod = bNew; } + + /// Spacing content + bool getSpacing() const { return mbSpacing; } + void setSpacing(bool bNew) { mbSpacing = bNew; } + }; + } // end of namespace svgreader +} // end of namespace svgio + +////////////////////////////////////////////////////////////////////////////// + +#endif //INCLUDED_SVGIO_SVGREADER_SVGTEXTPATHNODE_HXX + +// eof + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svgio/inc/svgio/svgreader/svgtoken.hxx b/svgio/inc/svgio/svgreader/svgtoken.hxx new file mode 100644 index 000000000000..c0c68fbef3ba --- /dev/null +++ b/svgio/inc/svgio/svgreader/svgtoken.hxx @@ -0,0 +1,194 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_SVGIO_SVGREADER_SVGTOKEN_HXX +#define INCLUDED_SVGIO_SVGREADER_SVGTOKEN_HXX + +#include <svgio/svgiodllapi.h> +#include <rtl/ustring.hxx> +#include <boost/unordered_map.hpp> + +////////////////////////////////////////////////////////////////////////////// + +namespace svgio +{ + namespace svgreader + { + // SVG token mapper with hashing + enum SVGToken + { + SVGTokenUnknown = 0, + + // diverse attribute tokens + SVGTokenWidth, + SVGTokenHeight, + SVGTokenViewBox, + SVGTokenTransform, + SVGTokenStyle, + SVGTokenD, + SVGTokenX, + SVGTokenY, + SVGTokenXmlns, + SVGTokenVersion, + SVGTokenId, + SVGTokenRx, + SVGTokenRy, + SVGTokenPoints, + SVGTokenDx, + SVGTokenDy, + SVGTokenRotate, + SVGTokenTextLength, + SVGTokenLengthAdjust, + SVGTokenFont, + SVGTokenFontFamily, + SVGTokenFontSize, + SVGTokenFontSizeAdjust, + SVGTokenFontStretch, + SVGTokenFontStyle, + SVGTokenFontVariant, + SVGTokenFontWeight, + SVGTokenDirection, + SVGTokenLetterSpacing, + SVGTokenTextDecoration, + SVGTokenUnicodeBidi, + SVGTokenWordSpacing, + SVGTokenCharacter, // not in the hash, just for simple text handling in SvgCharacterNode + SVGTokenTspan, + SVGTokenTref, + SVGTokenTextPath, + SVGTokenStartOffset, + SVGTokenMethod, + SVGTokenSpacing, + SVGTokenTextAlign, + SVGTokenPathLength, + SVGTokenType, + SVGTokenClass, + SVGTokenTextAnchor, + SVGTokenXmlSpace, + SVGTokenColor, + SVGTokenClipPathNode, + SVGTokenClipPathProperty, + SVGTokenMask, + SVGTokenClipPathUnits, + SVGTokenMaskUnits, + SVGTokenMaskContentUnits, + SVGTokenClipRule, + SVGTokenMarker, + SVGTokenMarkerStart, + SVGTokenMarkerMid, + SVGTokenMarkerEnd, + SVGTokenRefX, + SVGTokenRefY, + SVGTokenMarkerUnits, + SVGTokenMarkerWidth, + SVGTokenMarkerHeight, + SVGTokenOrient, + SVGTokenPattern, + SVGTokenPatternUnits, + SVGTokenPatternContentUnits, + SVGTokenPatternTransform, + SVGTokenOpacity, + + // AspectRatio and params + SVGTokenPreserveAspectRatio, + SVGTokenDefer, + SVGTokenNone, + SVGTokenXMinYMin, + SVGTokenXMidYMin, + SVGTokenXMaxYMin, + SVGTokenXMinYMid, + SVGTokenXMidYMid, + SVGTokenXMaxYMid, + SVGTokenXMinYMax, + SVGTokenXMidYMax, + SVGTokenXMaxYMax, + SVGTokenMeet, + SVGTokenSlice, + + // structural elements + SVGTokenDefs, + SVGTokenG, + SVGTokenSvg, + SVGTokenSymbol, + SVGTokenUse, + + // shape elements + SVGTokenCircle, + SVGTokenEllipse, + SVGTokenLine, + SVGTokenPath, + SVGTokenPolygon, + SVGTokenPolyline, + SVGTokenRect, + SVGTokenImage, + + // gradient elements and tokens + SVGTokenLinearGradient, + SVGTokenRadialGradient, + SVGTokenStop, + SVGTokenOffset, + SVGTokenX1, + SVGTokenY1, + SVGTokenX2, + SVGTokenY2, + SVGTokenCx, + SVGTokenCy, + SVGTokenFx, + SVGTokenFy, + SVGTokenR, + SVGTokenGradientUnits, + SVGTokenGradientTransform, + SVGTokenSpreadMethod, + SVGTokenXlinkHref, + SVGTokenStopColor, + SVGTokenStopOpacity, + + // fill tokens + SVGTokenFill, + SVGTokenFillOpacity, + SVGTokenFillRule, + + // stroke tokens + SVGTokenStroke, + SVGTokenStrokeDasharray, + SVGTokenStrokeDashoffset, + SVGTokenStrokeLinecap, + SVGTokenStrokeLinejoin, + SVGTokenStrokeMiterlimit, + SVGTokenStrokeOpacity, + SVGTokenStrokeWidth, + + // text tokens + SVGTokenText, + + SVGTokenLast + }; + + SVGToken StrToSVGToken(const rtl::OUString& rStr); + + } // end of namespace svgreader +} // end of namespace svgio + +////////////////////////////////////////////////////////////////////////////// + +#endif //INCLUDED_SVGIO_SVGREADER_SVGTOKEN_HXX + +// eof + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svgio/inc/svgio/svgreader/svgtools.hxx b/svgio/inc/svgio/svgreader/svgtools.hxx new file mode 100644 index 000000000000..5f9645e6d0cf --- /dev/null +++ b/svgio/inc/svgio/svgreader/svgtools.hxx @@ -0,0 +1,229 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_SVGIO_SVGREADER_SVGTOOLS_HXX +#define INCLUDED_SVGIO_SVGREADER_SVGTOOLS_HXX + +#include <svgio/svgiodllapi.h> +#include <drawinglayer/primitive2d/baseprimitive2d.hxx> +#include <basegfx/color/bcolor.hxx> +#include <basegfx/polygon/b2dpolypolygon.hxx> +#include <svgio/svgreader/svgpaint.hxx> +#include <vector> + +////////////////////////////////////////////////////////////////////////////// + +namespace svgio +{ + namespace svgreader + { +#ifdef DBG_UTIL + // error helper + void myAssert(const rtl::OUString& rMessage); +#endif + + // common non-token strings + struct commonStrings + { + static const rtl::OUString aStrUserSpaceOnUse; + static const rtl::OUString aStrObjectBoundingBox; + static const rtl::OUString aStrNonzero; + static const rtl::OUString aStrEvenOdd; + }; + + enum SvgUnits + { + userSpaceOnUse, + objectBoundingBox + }; + + enum NumberType + { + xcoordinate, + ycoordinate, + length + }; + + class InfoProvider + { + public: + virtual ~InfoProvider() {} + virtual const basegfx::B2DRange* getCurrentViewPort() const = 0; + virtual double getCurrentFontSize() const = 0; + virtual double getCurrentXHeight() const = 0; + }; + + enum SvgUnit + { + Unit_em = 0, // relative to current font size + Unit_ex, // relative to current x-height + + Unit_px, // 'user unit' + Unit_pt, // points, 1.25 px + Unit_pc, // 15.0 px + Unit_cm, // 35.43307 px + Unit_mm, // 3.543307 px + Unit_in, // 90 px + + Unit_percent // relative to range + }; + + class SvgNumber + { + private: + double mfNumber; + SvgUnit meUnit; + + /// bitfield + bool mbSet : 1; + + public: + SvgNumber() + : mfNumber(0.0), + meUnit(Unit_px), + mbSet(false) + { + } + + SvgNumber(double fNum, SvgUnit aSvgUnit = Unit_px, bool bSet = true) + : mfNumber(fNum), + meUnit(aSvgUnit), + mbSet(bSet) + { + } + + double getNumber() const + { + return mfNumber; + } + + SvgUnit getUnit() const + { + return meUnit; + } + + bool isSet() const + { + return mbSet; + } + + bool isPositive() const; + + double solve(const InfoProvider& rInfoProvider, NumberType aNumberType = length) const; + }; + + typedef ::std::vector< SvgNumber > SvgNumberVector; + + enum SvgAlign + { + Align_none, + Align_xMinYMin, + Align_xMidYMin, + Align_xMaxYMin, + Align_xMinYMid, + Align_xMidYMid, // default + Align_xMaxYMid, + Align_xMinYMax, + Align_xMidYMax, + Align_xMaxYMax + }; + + class SvgAspectRatio + { + private: + SvgAlign maSvgAlign; + + /// bitfield + bool mbDefer : 1; // default is false + bool mbMeetOrSlice : 1; // true = meet (default), false = slice + bool mbSet : 1; + + public: + SvgAspectRatio() + : maSvgAlign(Align_xMidYMid), + mbDefer(false), + mbMeetOrSlice(true), + mbSet(false) + { + } + + SvgAspectRatio(SvgAlign aSvgAlign, bool bDefer, bool bMeetOrSlice) + : maSvgAlign(aSvgAlign), + mbDefer(bDefer), + mbMeetOrSlice(bMeetOrSlice), + mbSet(true) + { + } + + /// data read access + SvgAlign getSvgAlign() const { return maSvgAlign; } + bool isDefer() const { return mbDefer; } + bool isMeetOrSlice() const { return mbMeetOrSlice; } + bool isSet() const { return mbSet; } + + /// tooling + static basegfx::B2DHomMatrix createLinearMapping(const basegfx::B2DRange& rTarget, const basegfx::B2DRange& rSource); + basegfx::B2DHomMatrix createMapping(const basegfx::B2DRange& rTarget, const basegfx::B2DRange& rSource) const; + }; + + void skip_char(const rtl::OUString& rCandidate, const sal_Unicode& rChar, sal_Int32& nPos, const sal_Int32 nLen); + void skip_char(const rtl::OUString& rCandidate, const sal_Unicode& rCharA, const sal_Unicode& rCharB, sal_Int32& nPos, const sal_Int32 nLen); + void copySign(const rtl::OUString& rCandidate, sal_Int32& nPos, rtl::OUStringBuffer& rTarget, const sal_Int32 nLen); + void copyNumber(const rtl::OUString& rCandidate, sal_Int32& nPos, rtl::OUStringBuffer& rTarget, const sal_Int32 nLen); + void copyHex(const rtl::OUString& rCandidate, sal_Int32& nPos, rtl::OUStringBuffer& rTarget, const sal_Int32 nLen); + void copyString(const rtl::OUString& rCandidate, sal_Int32& nPos, rtl::OUStringBuffer& rTarget, const sal_Int32 nLen); + void copyToLimiter(const rtl::OUString& rCandidate, const sal_Unicode& rLimiter, sal_Int32& nPos, rtl::OUStringBuffer& rTarget, const sal_Int32 nLen); + bool readNumber(const rtl::OUString& rCandidate, sal_Int32& nPos, double& fNum, const sal_Int32 nLen); + SvgUnit readUnit(const rtl::OUString& rCandidate, sal_Int32& nPos, const sal_Int32 nLen); + bool readNumberAndUnit(const rtl::OUString& rCandidate, sal_Int32& nPos, SvgNumber& aNum, const sal_Int32 nLen); + bool readAngle(const rtl::OUString& rCandidate, sal_Int32& nPos, double& fAngle, const sal_Int32 nLen); + sal_Int32 read_hex(const sal_Unicode& rChar); + bool match_colorKeyword(basegfx::BColor& rColor, const rtl::OUString& rName); + bool read_color(const rtl::OUString& rCandidate, basegfx::BColor& rColor); + basegfx::B2DRange readViewBox(const rtl::OUString& rCandidate, InfoProvider& rInfoProvider); + basegfx::B2DHomMatrix readTransform(const rtl::OUString& rCandidate, InfoProvider& rInfoProvider); + bool readSingleNumber(const rtl::OUString& rCandidate, SvgNumber& aNum); + bool readLocalUrl(const rtl::OUString& rCandidate, rtl::OUString& rURL); + bool readSvgPaint(const rtl::OUString& rCandidate, SvgPaint& rSvgPaint, rtl::OUString& rURL); + + bool readSvgNumberVector(const rtl::OUString& rCandidate, SvgNumberVector& rSvgNumberVector); + ::std::vector< double > solveSvgNumberVector(const SvgNumberVector& rInput, const InfoProvider& rInfoProvider, NumberType aNumberType = length); + + SvgAspectRatio readSvgAspectRatio(const rtl::OUString& rCandidate); + + typedef ::std::vector< rtl::OUString > SvgStringVector; + bool readSvgStringVector(const rtl::OUString& rCandidate, SvgStringVector& rSvgStringVector); + + void readImageLink(const rtl::OUString& rCandidate, rtl::OUString& rXLink, rtl::OUString& rUrl, rtl::OUString& rMimeType, rtl::OUString& rData); + + rtl::OUString convert(const rtl::OUString& rCandidate, const sal_Unicode& rPattern, const sal_Unicode& rNew, bool bRemove); + rtl::OUString consolidateContiguosSpace(const rtl::OUString& rCandidate); + rtl::OUString whiteSpaceHandlingDefault(const rtl::OUString& rCandidate); + rtl::OUString whiteSpaceHandlingPreserve(const rtl::OUString& rCandidate); + + } // end of namespace svgreader +} // end of namespace svgio + +////////////////////////////////////////////////////////////////////////////// + +#endif //INCLUDED_SVGIO_SVGREADER_SVGTOOLS_HXX + +// eof + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svgio/inc/svgio/svgreader/svgtrefnode.hxx b/svgio/inc/svgio/svgreader/svgtrefnode.hxx new file mode 100644 index 000000000000..782faa17d089 --- /dev/null +++ b/svgio/inc/svgio/svgreader/svgtrefnode.hxx @@ -0,0 +1,65 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_SVGIO_SVGREADER_SVGTREFNODE_HXX +#define INCLUDED_SVGIO_SVGREADER_SVGTREFNODE_HXX + +#include <svgio/svgiodllapi.h> +#include <svgio/svgreader/svgnode.hxx> +#include <svgio/svgreader/svgstyleattributes.hxx> +#include <svgio/svgreader/svgtextnode.hxx> + +////////////////////////////////////////////////////////////////////////////// + +namespace svgio +{ + namespace svgreader + { + class SvgTrefNode : public SvgNode + { + private: + /// use styles + SvgStyleAttributes maSvgStyleAttributes; + + /// link to text content. If maXLink + /// is set, the node can be fetched on demand + rtl::OUString maXLink; + + public: + SvgTrefNode( + SvgDocument& rDocument, + SvgNode* pParent); + virtual ~SvgTrefNode(); + + virtual const SvgStyleAttributes* getSvgStyleAttributes() const; + virtual void parseAttribute(const rtl::OUString& rTokenName, SVGToken aSVGToken, const rtl::OUString& aContent); + + /// access to referenced SvgTextNode + const SvgTextNode* getReferencedSvgTextNode() const; + }; + } // end of namespace svgreader +} // end of namespace svgio + +////////////////////////////////////////////////////////////////////////////// + +#endif //INCLUDED_SVGIO_SVGREADER_SVGTREFNODE_HXX + +// eof + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svgio/inc/svgio/svgreader/svgtspannode.hxx b/svgio/inc/svgio/svgreader/svgtspannode.hxx new file mode 100644 index 000000000000..24bf96812fb7 --- /dev/null +++ b/svgio/inc/svgio/svgreader/svgtspannode.hxx @@ -0,0 +1,64 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_SVGIO_SVGREADER_SVGTSPANNODE_HXX +#define INCLUDED_SVGIO_SVGREADER_SVGTSPANNODE_HXX + +#include <svgio/svgiodllapi.h> +#include <svgio/svgreader/svgcharacternode.hxx> +#include <svgio/svgreader/svgstyleattributes.hxx> +#include <svgio/svgreader/svgtools.hxx> + +////////////////////////////////////////////////////////////////////////////// + +namespace svgio +{ + namespace svgreader + { + class SvgTspanNode : public SvgNode + { + private: + /// use styles + SvgStyleAttributes maSvgStyleAttributes; + + /// variable scan values, dependent of given XAttributeList + SvgTextPositions maSvgTextPositions; + + public: + SvgTspanNode( + SvgDocument& rDocument, + SvgNode* pParent); + virtual ~SvgTspanNode(); + + virtual const SvgStyleAttributes* getSvgStyleAttributes() const; + virtual void parseAttribute(const rtl::OUString& rTokenName, SVGToken aSVGToken, const rtl::OUString& aContent); + + /// access to SvgTextPositions + const SvgTextPositions& getSvgTextPositions() const { return maSvgTextPositions; } + }; + } // end of namespace svgreader +} // end of namespace svgio + +////////////////////////////////////////////////////////////////////////////// + +#endif //INCLUDED_SVGIO_SVGREADER_SVGTSPANNODE_HXX + +// eof + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svgio/inc/svgio/svgreader/svgusenode.hxx b/svgio/inc/svgio/svgreader/svgusenode.hxx new file mode 100644 index 000000000000..d7613e68092f --- /dev/null +++ b/svgio/inc/svgio/svgreader/svgusenode.hxx @@ -0,0 +1,89 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_SVGIO_SVGREADER_USENODE_HXX +#define INCLUDED_SVGIO_SVGREADER_USENODE_HXX + +#include <svgio/svgiodllapi.h> +#include <svgio/svgreader/svgnode.hxx> +#include <svgio/svgreader/svgstyleattributes.hxx> + +////////////////////////////////////////////////////////////////////////////// + +namespace svgio +{ + namespace svgreader + { + class SvgUseNode : public SvgNode + { + private: + /// use styles + SvgStyleAttributes maSvgStyleAttributes; + + /// variable scan values, dependent of given XAttributeList + basegfx::B2DHomMatrix* mpaTransform; + SvgNumber maX; + SvgNumber maY; + SvgNumber maWidth; + SvgNumber maHeight; + + /// link to content. If maXLink is set, the node can be fetched + // on demand + rtl::OUString maXLink; + + public: + SvgUseNode( + SvgDocument& rDocument, + SvgNode* pParent); + virtual ~SvgUseNode(); + + virtual const SvgStyleAttributes* getSvgStyleAttributes() const; + virtual void parseAttribute(const rtl::OUString& rTokenName, SVGToken aSVGToken, const rtl::OUString& aContent); + virtual void decomposeSvgNode(drawinglayer::primitive2d::Primitive2DSequence& rTarget, bool bReferenced) const; + + /// transform content + const basegfx::B2DHomMatrix* getTransform() const { return mpaTransform; } + void setTransform(const basegfx::B2DHomMatrix* pMatrix = 0) { if(mpaTransform) delete mpaTransform; mpaTransform = 0; if(pMatrix) mpaTransform = new basegfx::B2DHomMatrix(*pMatrix); } + + /// x content + const SvgNumber& getX() const { return maX; } + void setX(const SvgNumber& rX = SvgNumber()) { maX = rX; } + + /// y content + const SvgNumber& getY() const { return maY; } + void setY(const SvgNumber& rY = SvgNumber()) { maY = rY; } + + /// width content + const SvgNumber& getWidth() const { return maWidth; } + void setWidth(const SvgNumber& rWidth = SvgNumber()) { maWidth = rWidth; } + + /// height content + const SvgNumber& getHeight() const { return maHeight; } + void setHeight(const SvgNumber& rHeight = SvgNumber()) { maHeight = rHeight; } + }; + } // end of namespace svgreader +} // end of namespace svgio + +////////////////////////////////////////////////////////////////////////////// + +#endif //INCLUDED_SVGIO_SVGREADER_USENODE_HXX + +// eof + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svgio/prj/build.lst b/svgio/prj/build.lst new file mode 100644 index 000000000000..ff858ab1ddda --- /dev/null +++ b/svgio/prj/build.lst @@ -0,0 +1,2 @@ +dl svgio : sal basegfx drawinglayer cppuhelper cppu svtools NULL +dl svgio\prj nmake - all svgio_prj NULL diff --git a/svgio/prj/d.lst b/svgio/prj/d.lst new file mode 100644 index 000000000000..e69de29bb2d1 --- /dev/null +++ b/svgio/prj/d.lst diff --git a/svgio/prj/makefile.mk b/svgio/prj/makefile.mk new file mode 100644 index 000000000000..f3e47cb7f1a3 --- /dev/null +++ b/svgio/prj/makefile.mk @@ -0,0 +1,33 @@ +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# This file incorporates work covered by the following license notice: +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed +# with this work for additional information regarding copyright +# ownership. The ASF licenses this file to you under the Apache +# License, Version 2.0 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.apache.org/licenses/LICENSE-2.0 . +# + + + +PRJ=.. +TARGET=prj + +.INCLUDE : settings.mk + +.IF "$(VERBOSE)"!="" +VERBOSEFLAG := +.ELSE +VERBOSEFLAG := -s +.ENDIF + +all: + cd $(PRJ) && $(GNUMAKE) $(VERBOSEFLAG) -r -j$(MAXPROCESS) $(gb_MAKETARGET) && $(GNUMAKE) $(VERBOSEFLAG) -r deliverlog diff --git a/svgio/source/svgreader/svgcharacternode.cxx b/svgio/source/svgreader/svgcharacternode.cxx new file mode 100644 index 000000000000..552db36ea939 --- /dev/null +++ b/svgio/source/svgreader/svgcharacternode.cxx @@ -0,0 +1,740 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <svgio/svgreader/svgcharacternode.hxx> +#include <svgio/svgreader/svgstyleattributes.hxx> +#include <drawinglayer/attribute/fontattribute.hxx> +#include <drawinglayer/primitive2d/textprimitive2d.hxx> +#include <drawinglayer/primitive2d/textlayoutdevice.hxx> +#include <drawinglayer/primitive2d/textbreakuphelper.hxx> +#include <drawinglayer/primitive2d/groupprimitive2d.hxx> +#include <drawinglayer/primitive2d/textdecoratedprimitive2d.hxx> + +////////////////////////////////////////////////////////////////////////////// + +namespace svgio +{ + namespace svgreader + { + SvgTextPositions::SvgTextPositions() + : maX(), + maY(), + maDx(), + maDy(), + maRotate(), + maTextLength(), + mbLengthAdjust(true) + { + } + + void SvgTextPositions::parseTextPositionAttributes(const rtl::OUString& /*rTokenName*/, SVGToken aSVGToken, const rtl::OUString& aContent) + { + // parse own + switch(aSVGToken) + { + case SVGTokenX: + { + if(aContent.getLength()) + { + SvgNumberVector aVector; + + if(readSvgNumberVector(aContent, aVector)) + { + setX(aVector); + } + } + break; + } + case SVGTokenY: + { + if(aContent.getLength()) + { + SvgNumberVector aVector; + + if(readSvgNumberVector(aContent, aVector)) + { + setY(aVector); + } + } + break; + } + case SVGTokenDx: + { + if(aContent.getLength()) + { + SvgNumberVector aVector; + + if(readSvgNumberVector(aContent, aVector)) + { + setDx(aVector); + } + } + break; + } + case SVGTokenDy: + { + if(aContent.getLength()) + { + SvgNumberVector aVector; + + if(readSvgNumberVector(aContent, aVector)) + { + setDy(aVector); + } + } + break; + } + case SVGTokenRotate: + { + if(aContent.getLength()) + { + SvgNumberVector aVector; + + if(readSvgNumberVector(aContent, aVector)) + { + setRotate(aVector); + } + } + break; + } + case SVGTokenTextLength: + { + SvgNumber aNum; + + if(readSingleNumber(aContent, aNum)) + { + if(aNum.isPositive()) + { + setTextLength(aNum); + } + } + break; + } + case SVGTokenLengthAdjust: + { + if(aContent.getLength()) + { + static rtl::OUString aStrSpacing(rtl::OUString::createFromAscii("spacing")); + static rtl::OUString aStrSpacingAndGlyphs(rtl::OUString::createFromAscii("spacingAndGlyphs")); + + if(aContent.match(aStrSpacing)) + { + setLengthAdjust(true); + } + else if(aContent.match(aStrSpacingAndGlyphs)) + { + setLengthAdjust(false); + } + } + break; + } + default: + { + break; + } + } + } + + } // end of namespace svgreader +} // end of namespace svgio + +////////////////////////////////////////////////////////////////////////////// + +namespace svgio +{ + namespace svgreader + { + class localTextBreakupHelper : public drawinglayer::primitive2d::TextBreakupHelper + { + private: + SvgTextPosition& mrSvgTextPosition; + + protected: + /// allow user callback to allow changes to the new TextTransformation. Default + /// does nothing. + virtual bool allowChange(sal_uInt32 nCount, basegfx::B2DHomMatrix& rNewTransform, sal_uInt32 nIndex, sal_uInt32 nLength); + + public: + localTextBreakupHelper( + const drawinglayer::primitive2d::TextSimplePortionPrimitive2D& rSource, + SvgTextPosition& rSvgTextPosition) + : drawinglayer::primitive2d::TextBreakupHelper(rSource), + mrSvgTextPosition(rSvgTextPosition) + { + } + }; + + bool localTextBreakupHelper::allowChange(sal_uInt32 /*nCount*/, basegfx::B2DHomMatrix& rNewTransform, sal_uInt32 /*nIndex*/, sal_uInt32 /*nLength*/) + { + const double fRotation(mrSvgTextPosition.consumeRotation()); + + if(0.0 != fRotation) + { + const basegfx::B2DPoint aBasePoint(rNewTransform * basegfx::B2DPoint(0.0, 0.0)); + + rNewTransform.translate(-aBasePoint.getX(), -aBasePoint.getY()); + rNewTransform.rotate(fRotation); + rNewTransform.translate(aBasePoint.getX(), aBasePoint.getY()); + } + + return true; + } + + } // end of namespace svgreader +} // end of namespace svgio + +////////////////////////////////////////////////////////////////////////////// + +namespace svgio +{ + namespace svgreader + { + SvgCharacterNode::SvgCharacterNode( + SvgDocument& rDocument, + SvgNode* pParent, + const rtl::OUString& rText) + : SvgNode(SVGTokenCharacter, rDocument, pParent), + maText(rText) + { + } + + SvgCharacterNode::~SvgCharacterNode() + { + } + + const SvgStyleAttributes* SvgCharacterNode::getSvgStyleAttributes() const + { + // no own style, use parent's + if(getParent()) + { + return getParent()->getSvgStyleAttributes(); + } + else + { + return 0; + } + } + + drawinglayer::primitive2d::TextSimplePortionPrimitive2D* SvgCharacterNode::createSimpleTextPrimitive( + SvgTextPosition& rSvgTextPosition, + const SvgStyleAttributes& rSvgStyleAttributes) const + { + // prepare retval, index and length + drawinglayer::primitive2d::TextSimplePortionPrimitive2D* pRetval = 0; + sal_uInt32 nIndex(0); + sal_uInt32 nLength(getText().getLength()); + + if(nLength) + { + // prepare FontAttribute + const rtl::OUString aFontFamily = rSvgStyleAttributes.getFontFamily().empty() ? + rtl::OUString(rtl::OUString::createFromAscii("Times New Roman")) : + rSvgStyleAttributes.getFontFamily()[0]; + const ::FontWeight nFontWeight(getVclFontWeight(rSvgStyleAttributes.getFontWeight())); + bool bSymbol(false); + bool bVertical(false); + bool bItalic(FontStyle_italic == rSvgStyleAttributes.getFontStyle() || FontStyle_oblique == rSvgStyleAttributes.getFontStyle()); + bool bMonospaced(false); + bool bOutline(false); + bool bRTL(false); + bool bBiDiStrong(false); + + const drawinglayer::attribute::FontAttribute aFontAttribute( + aFontFamily, + rtl::OUString(), + nFontWeight, + bSymbol, + bVertical, + bItalic, + bMonospaced, + bOutline, + bRTL, + bBiDiStrong); + + // prepare FontSize + double fFontWidth(rSvgStyleAttributes.getFontSize().solve(*this, length)); + double fFontHeight(fFontWidth); + + // prepare locale + ::com::sun::star::lang::Locale aLocale; + + // prepare TextLayouterDevice + drawinglayer::primitive2d::TextLayouterDevice aTextLayouterDevice; + aTextLayouterDevice.setFontAttribute(aFontAttribute, fFontWidth, fFontHeight, aLocale); + + // prepare TextArray + ::std::vector< double > aTextArray(rSvgTextPosition.getX()); + + if(!aTextArray.empty() && aTextArray.size() < nLength) + { + const sal_uInt32 nArray(aTextArray.size()); + + if(nArray < nLength) + { + double fStartX(0.0); + + if(rSvgTextPosition.getParent() && rSvgTextPosition.getParent()->getAbsoluteX()) + { + fStartX = rSvgTextPosition.getParent()->getPosition().getX(); + } + else + { + fStartX = aTextArray[nArray - 1]; + } + + ::std::vector< double > aExtendArray(aTextLayouterDevice.getTextArray(getText(), nArray, nLength - nArray)); + aTextArray.reserve(nLength); + + for(sal_uInt32 a(0); a < aExtendArray.size(); a++) + { + aTextArray.push_back(aExtendArray[a] + fStartX); + } + } + } + + // get current TextPosition and TextWidth in units + basegfx::B2DPoint aPosition(rSvgTextPosition.getPosition()); + double fTextWidth(aTextLayouterDevice.getTextWidth(getText(), nIndex, nLength)); + + // check for user-given TextLength + if(0.0 != rSvgTextPosition.getTextLength() + && !basegfx::fTools::equal(fTextWidth, rSvgTextPosition.getTextLength())) + { + const double fFactor(rSvgTextPosition.getTextLength() / fTextWidth); + + if(rSvgTextPosition.getLengthAdjust()) + { + // spacing, need to create and expand TextArray + if(aTextArray.empty()) + { + aTextArray = aTextLayouterDevice.getTextArray(getText(), nIndex, nLength); + } + + for(sal_uInt32 a(0); a < aTextArray.size(); a++) + { + aTextArray[a] *= fFactor; + } + } + else + { + // spacing and glyphs, just apply to FontWidth + fFontWidth *= fFactor; + } + + fTextWidth = rSvgTextPosition.getTextLength(); + } + + // get TextAlign + TextAlign aTextAlign(rSvgStyleAttributes.getTextAlign()); + + // map TextAnchor to TextAlign, there seems not to be a difference + if(TextAnchor_notset != rSvgStyleAttributes.getTextAnchor()) + { + switch(rSvgStyleAttributes.getTextAnchor()) + { + case TextAnchor_start: + { + aTextAlign = TextAlign_left; + break; + } + case TextAnchor_middle: + { + aTextAlign = TextAlign_center; + break; + } + case TextAnchor_end: + { + aTextAlign = TextAlign_right; + break; + } + default: + { + break; + } + } + } + + // apply TextAlign + switch(aTextAlign) + { + case TextAlign_right: + { + aPosition.setX(aPosition.getX() - fTextWidth); + break; + } + case TextAlign_center: + { + aPosition.setX(aPosition.getX() - (fTextWidth * 0.5)); + break; + } + case TextAlign_notset: + case TextAlign_left: + case TextAlign_justify: + { + // TextAlign_notset, TextAlign_left: nothing to do + // TextAlign_justify is not clear currently; handle as TextAlign_left + break; + } + } + + // get fill color + const basegfx::BColor aFill(rSvgStyleAttributes.getFill() + ? *rSvgStyleAttributes.getFill() + : basegfx::BColor(0.0, 0.0, 0.0)); + + // prepare TextTransformation + basegfx::B2DHomMatrix aTextTransform; + + aTextTransform.scale(fFontWidth, fFontHeight); + aTextTransform.translate(aPosition.getX(), aPosition.getY()); + + // check TextDecoration and if TextDecoratedPortionPrimitive2D is needed + const TextDecoration aDeco(rSvgStyleAttributes.getTextDecoration()); + + if(TextDecoration_underline == aDeco + || TextDecoration_overline == aDeco + || TextDecoration_line_through == aDeco) + { + // get the fill for decroation as described by SVG. We cannot + // have different stroke colors/definitions for those, though + const SvgStyleAttributes* pDecoDef = rSvgStyleAttributes.getTextDecorationDefiningSvgStyleAttributes(); + const basegfx::BColor aDecoColor(pDecoDef && pDecoDef->getFill() ? *pDecoDef->getFill() : aFill); + + // create decorated text primitive + pRetval = new drawinglayer::primitive2d::TextDecoratedPortionPrimitive2D( + aTextTransform, + getText(), + nIndex, + nLength, + aTextArray, + aFontAttribute, + aLocale, + aFill, + + // extra props for decorated + aDecoColor, + aDecoColor, + TextDecoration_overline == aDeco ? drawinglayer::primitive2d::TEXT_LINE_SINGLE : drawinglayer::primitive2d::TEXT_LINE_NONE, + TextDecoration_underline == aDeco ? drawinglayer::primitive2d::TEXT_LINE_SINGLE : drawinglayer::primitive2d::TEXT_LINE_NONE, + false, + TextDecoration_line_through == aDeco ? drawinglayer::primitive2d::TEXT_STRIKEOUT_SINGLE : drawinglayer::primitive2d::TEXT_STRIKEOUT_NONE, + false, + drawinglayer::primitive2d::TEXT_EMPHASISMARK_NONE, + true, + false, + drawinglayer::primitive2d::TEXT_RELIEF_NONE, + false); + } + else + { + // create text primitive + pRetval = new drawinglayer::primitive2d::TextSimplePortionPrimitive2D( + aTextTransform, + getText(), + nIndex, + nLength, + aTextArray, + aFontAttribute, + aLocale, + aFill); + } + + // advance current TextPosition + rSvgTextPosition.setPosition(rSvgTextPosition.getPosition() + basegfx::B2DVector(fTextWidth, 0.0)); + } + + return pRetval; + } + + void SvgCharacterNode::decomposeTextWithStyle( + drawinglayer::primitive2d::Primitive2DSequence& rTarget, + SvgTextPosition& rSvgTextPosition, + const SvgStyleAttributes& rSvgStyleAttributes) const + { + const drawinglayer::primitive2d::Primitive2DReference xRef( + createSimpleTextPrimitive( + rSvgTextPosition, + rSvgStyleAttributes)); + + if(xRef.is()) + { + if(!rSvgTextPosition.isRotated()) + { + drawinglayer::primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(rTarget, xRef); + } + else + { + // need to apply rotations to each character as given + const drawinglayer::primitive2d::TextSimplePortionPrimitive2D* pCandidate = + dynamic_cast< const drawinglayer::primitive2d::TextSimplePortionPrimitive2D* >(xRef.get()); + + if(pCandidate) + { + const localTextBreakupHelper alocalTextBreakupHelper(*pCandidate, rSvgTextPosition); + const drawinglayer::primitive2d::Primitive2DSequence aResult( + alocalTextBreakupHelper.getResult(drawinglayer::primitive2d::BreakupUnit_character)); + + if(aResult.hasElements()) + { + drawinglayer::primitive2d::appendPrimitive2DSequenceToPrimitive2DSequence(rTarget, aResult); + } + + // also consume for the implied single space + rSvgTextPosition.consumeRotation(); + } + else + { + OSL_ENSURE(false, "Used primitive is not a text primitive (!)"); + } + } + } + } + + void SvgCharacterNode::whiteSpaceHandling() + { + if(XmlSpace_default == getXmlSpace()) + { + maText = whiteSpaceHandlingDefault(maText); + } + else + { + maText = whiteSpaceHandlingPreserve(maText); + } + } + + void SvgCharacterNode::addGap() + { + maText += rtl::OUString(sal_Unicode(' ')); + } + + void SvgCharacterNode::concatenate(const rtl::OUString& rText) + { + maText += rText; + } + + void SvgCharacterNode::decomposeText(drawinglayer::primitive2d::Primitive2DSequence& rTarget, SvgTextPosition& rSvgTextPosition) const + { + if(getText().getLength()) + { + const SvgStyleAttributes* pSvgStyleAttributes = getSvgStyleAttributes(); + + if(pSvgStyleAttributes) + { + decomposeTextWithStyle(rTarget, rSvgTextPosition, *pSvgStyleAttributes); + } + } + } + + } // end of namespace svgreader +} // end of namespace svgio + +////////////////////////////////////////////////////////////////////////////// + +namespace svgio +{ + namespace svgreader + { + SvgTextPosition::SvgTextPosition( + SvgTextPosition* pParent, + const InfoProvider& rInfoProvider, + const SvgTextPositions& rSvgTextPositions) + : mpParent(pParent), + maX(), // computed below + maY(), // computed below + maRotate(solveSvgNumberVector(rSvgTextPositions.getRotate(), rInfoProvider, length)), + mfTextLength(0.0), + maPosition(), // computed below + mnRotationIndex(0), + mbLengthAdjust(rSvgTextPositions.getLengthAdjust()), + mbAbsoluteX(false), + mbAbsoluteY(false) + { + // get TextLength if provided + if(rSvgTextPositions.getTextLength().isSet()) + { + mfTextLength = rSvgTextPositions.getTextLength().solve(rInfoProvider, length); + } + + // SVG does not really define in which units a rotate for Text/TSpan is given, + // but it seems to be degrees. Convert here to radians + if(!maRotate.empty()) + { + const double fFactor(F_PI / 180.0); + + for(sal_uInt32 a(0); a < maRotate.size(); a++) + { + maRotate[a] *= fFactor; + } + } + + // get text positions X + const sal_uInt32 nSizeX(rSvgTextPositions.getX().size()); + + if(nSizeX) + { + // we have absolute positions, get first one as current text position X + maPosition.setX(rSvgTextPositions.getX()[0].solve(rInfoProvider, xcoordinate)); + mbAbsoluteX = true; + + if(nSizeX > 1) + { + // fill deltas to maX + maX.reserve(nSizeX); + + for(sal_uInt32 a(1); a < nSizeX; a++) + { + maX.push_back(rSvgTextPositions.getX()[a].solve(rInfoProvider, xcoordinate) - maPosition.getX()); + } + } + } + else + { + // no absolute position, get from parent + if(pParent) + { + maPosition.setX(pParent->getPosition().getX()); + } + + const sal_uInt32 nSizeDx(rSvgTextPositions.getDx().size()); + + if(nSizeDx) + { + // relative positions given, translate position derived from parent + maPosition.setX(maPosition.getX() + rSvgTextPositions.getDx()[0].solve(rInfoProvider, xcoordinate)); + + if(nSizeDx > 1) + { + // fill deltas to maX + maX.reserve(nSizeDx); + + for(sal_uInt32 a(1); a < nSizeDx; a++) + { + maX.push_back(rSvgTextPositions.getDx()[a].solve(rInfoProvider, xcoordinate)); + } + } + } + } + + // get text positions Y + const sal_uInt32 nSizeY(rSvgTextPositions.getY().size()); + + if(nSizeY) + { + // we have absolute positions, get first one as current text position Y + maPosition.setY(rSvgTextPositions.getY()[0].solve(rInfoProvider, ycoordinate)); + mbAbsoluteX = true; + + if(nSizeY > 1) + { + // fill deltas to maY + maY.reserve(nSizeY); + + for(sal_uInt32 a(1); a < nSizeY; a++) + { + maY.push_back(rSvgTextPositions.getY()[a].solve(rInfoProvider, ycoordinate) - maPosition.getY()); + } + } + } + else + { + // no absolute position, get from parent + if(pParent) + { + maPosition.setY(pParent->getPosition().getY()); + } + + const sal_uInt32 nSizeDy(rSvgTextPositions.getDy().size()); + + if(nSizeDy) + { + // relative positions given, translate position derived from parent + maPosition.setY(maPosition.getY() + rSvgTextPositions.getDy()[0].solve(rInfoProvider, ycoordinate)); + + if(nSizeDy > 1) + { + // fill deltas to maY + maY.reserve(nSizeDy); + + for(sal_uInt32 a(1); a < nSizeDy; a++) + { + maY.push_back(rSvgTextPositions.getDy()[a].solve(rInfoProvider, ycoordinate)); + } + } + } + } + } + + bool SvgTextPosition::isRotated() const + { + if(maRotate.empty()) + { + if(getParent()) + { + return getParent()->isRotated(); + } + else + { + return false; + } + } + else + { + return true; + } + } + + double SvgTextPosition::consumeRotation() + { + double fRetval(0.0); + + if(maRotate.empty()) + { + if(getParent()) + { + fRetval = mpParent->consumeRotation(); + } + else + { + fRetval = 0.0; + } + } + else + { + const sal_uInt32 nSize(maRotate.size()); + + if(mnRotationIndex < nSize) + { + fRetval = maRotate[mnRotationIndex++]; + } + else + { + fRetval = maRotate[nSize - 1]; + } + } + + return fRetval; + } + + } // end of namespace svgreader +} // end of namespace svgio + +////////////////////////////////////////////////////////////////////////////// +// eof + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svgio/source/svgreader/svgcirclenode.cxx b/svgio/source/svgreader/svgcirclenode.cxx new file mode 100644 index 000000000000..b9ef1f7bd624 --- /dev/null +++ b/svgio/source/svgreader/svgcirclenode.cxx @@ -0,0 +1,155 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <svgio/svgreader/svgcirclenode.hxx> +#include <basegfx/polygon/b2dpolygon.hxx> +#include <basegfx/polygon/b2dpolygontools.hxx> + +////////////////////////////////////////////////////////////////////////////// + +namespace svgio +{ + namespace svgreader + { + SvgCircleNode::SvgCircleNode( + SvgDocument& rDocument, + SvgNode* pParent) + : SvgNode(SVGTokenCircle, rDocument, pParent), + maSvgStyleAttributes(*this), + maCx(0), + maCy(0), + maR(0), + mpaTransform(0) + { + } + + SvgCircleNode::~SvgCircleNode() + { + if(mpaTransform) delete mpaTransform; + } + + const SvgStyleAttributes* SvgCircleNode::getSvgStyleAttributes() const + { + static rtl::OUString aClassStr(rtl::OUString::createFromAscii("circle")); + maSvgStyleAttributes.checkForCssStyle(aClassStr); + + return &maSvgStyleAttributes; + } + + void SvgCircleNode::parseAttribute(const rtl::OUString& rTokenName, SVGToken aSVGToken, const rtl::OUString& aContent) + { + // call parent + SvgNode::parseAttribute(rTokenName, aSVGToken, aContent); + + // read style attributes + maSvgStyleAttributes.parseStyleAttribute(rTokenName, aSVGToken, aContent); + + // parse own + switch(aSVGToken) + { + case SVGTokenStyle: + { + maSvgStyleAttributes.readStyle(aContent); + break; + } + case SVGTokenCx: + { + SvgNumber aNum; + + if(readSingleNumber(aContent, aNum)) + { + setCx(aNum); + } + break; + } + case SVGTokenCy: + { + SvgNumber aNum; + + if(readSingleNumber(aContent, aNum)) + { + setCy(aNum); + } + break; + } + case SVGTokenR: + { + SvgNumber aNum; + + if(readSingleNumber(aContent, aNum)) + { + if(aNum.isPositive()) + { + setR(aNum); + } + } + break; + } + case SVGTokenTransform: + { + const basegfx::B2DHomMatrix aMatrix(readTransform(aContent, *this)); + + if(!aMatrix.isIdentity()) + { + setTransform(&aMatrix); + } + break; + } + default: + { + break; + } + } + } + + void SvgCircleNode::decomposeSvgNode(drawinglayer::primitive2d::Primitive2DSequence& rTarget, bool /*bReferenced*/) const + { + const SvgStyleAttributes* pStyle = getSvgStyleAttributes(); + + if(pStyle && getR().isSet()) + { + const double fR(getR().solve(*this, xcoordinate)); + + if(fR > 0.0) + { + const basegfx::B2DPolygon aPath( + basegfx::tools::createPolygonFromCircle( + basegfx::B2DPoint( + getCx().isSet() ? getCx().solve(*this, xcoordinate) : 0.0, + getCy().isSet() ? getCy().solve(*this, ycoordinate) : 0.0), + fR)); + + drawinglayer::primitive2d::Primitive2DSequence aNewTarget; + + pStyle->add_path(basegfx::B2DPolyPolygon(aPath), aNewTarget); + + if(aNewTarget.hasElements()) + { + pStyle->add_postProcess(rTarget, aNewTarget, getTransform()); + } + } + } + } + } // end of namespace svgreader +} // end of namespace svgio + +////////////////////////////////////////////////////////////////////////////// +// eof + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svgio/source/svgreader/svgclippathnode.cxx b/svgio/source/svgreader/svgclippathnode.cxx new file mode 100644 index 000000000000..5c271400d5f0 --- /dev/null +++ b/svgio/source/svgreader/svgclippathnode.cxx @@ -0,0 +1,203 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <svgio/svgreader/svgclippathnode.hxx> +#include <drawinglayer/primitive2d/transformprimitive2d.hxx> +#include <drawinglayer/primitive2d/maskprimitive2d.hxx> +#include <basegfx/matrix/b2dhommatrixtools.hxx> +#include <drawinglayer/geometry/viewinformation2d.hxx> +#include <drawinglayer/processor2d/contourextractor2d.hxx> +#include <basegfx/polygon/b2dpolypolygoncutter.hxx> + +////////////////////////////////////////////////////////////////////////////// + +namespace svgio +{ + namespace svgreader + { + SvgClipPathNode::SvgClipPathNode( + SvgDocument& rDocument, + SvgNode* pParent) + : SvgNode(SVGTokenClipPathNode, rDocument, pParent), + maSvgStyleAttributes(*this), + mpaTransform(0), + maClipPathUnits(userSpaceOnUse) + { + } + + SvgClipPathNode::~SvgClipPathNode() + { + if(mpaTransform) delete mpaTransform; + } + + const SvgStyleAttributes* SvgClipPathNode::getSvgStyleAttributes() const + { + return &maSvgStyleAttributes; + } + + void SvgClipPathNode::parseAttribute(const rtl::OUString& rTokenName, SVGToken aSVGToken, const rtl::OUString& aContent) + { + // call parent + SvgNode::parseAttribute(rTokenName, aSVGToken, aContent); + + // read style attributes + maSvgStyleAttributes.parseStyleAttribute(rTokenName, aSVGToken, aContent); + + // parse own + switch(aSVGToken) + { + case SVGTokenStyle: + { + maSvgStyleAttributes.readStyle(aContent); + break; + } + case SVGTokenTransform: + { + const basegfx::B2DHomMatrix aMatrix(readTransform(aContent, *this)); + + if(!aMatrix.isIdentity()) + { + setTransform(&aMatrix); + } + break; + } + case SVGTokenClipPathUnits: + { + if(aContent.getLength()) + { + if(aContent.match(commonStrings::aStrUserSpaceOnUse, 0)) + { + setClipPathUnits(userSpaceOnUse); + } + else if(aContent.match(commonStrings::aStrObjectBoundingBox, 0)) + { + setClipPathUnits(objectBoundingBox); + } + } + break; + } + default: + { + break; + } + } + } + + void SvgClipPathNode::decomposeSvgNode(drawinglayer::primitive2d::Primitive2DSequence& rTarget, bool bReferenced) const + { + drawinglayer::primitive2d::Primitive2DSequence aNewTarget; + + // decompose childs + SvgNode::decomposeSvgNode(aNewTarget, bReferenced); + + if(aNewTarget.hasElements()) + { + if(getTransform()) + { + // create embedding group element with transformation + const drawinglayer::primitive2d::Primitive2DReference xRef( + new drawinglayer::primitive2d::TransformPrimitive2D( + *getTransform(), + aNewTarget)); + + drawinglayer::primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(rTarget, xRef); + } + else + { + // append to current target + drawinglayer::primitive2d::appendPrimitive2DSequenceToPrimitive2DSequence(rTarget, aNewTarget); + } + } + } + + void SvgClipPathNode::apply(drawinglayer::primitive2d::Primitive2DSequence& rContent) const + { + if(rContent.hasElements()) + { + const drawinglayer::geometry::ViewInformation2D aViewInformation2D; + drawinglayer::primitive2d::Primitive2DSequence aClipTarget; + basegfx::B2DPolyPolygon aClipPolyPolygon; + + // get clipPath definition as primitives + decomposeSvgNode(aClipTarget, true); + + if(aClipTarget.hasElements()) + { + // extract filled plygons as base for a mask PolyPolygon + drawinglayer::processor2d::ContourExtractor2D aExtractor(aViewInformation2D, true); + + aExtractor.process(aClipTarget); + + const basegfx::B2DPolyPolygonVector& rResult(aExtractor.getExtractedContour()); + const sal_uInt32 nSize(rResult.size()); + + if(nSize > 1) + { + // merge to single clipPolyPolygon + aClipPolyPolygon = basegfx::tools::mergeToSinglePolyPolygon(rResult); + } + else + { + aClipPolyPolygon = rResult[0]; + } + } + + if(aClipPolyPolygon.count()) + { + if(objectBoundingBox == getClipPathUnits()) + { + // clip is object-relative, transform using content transformation + const basegfx::B2DRange aContentRange( + drawinglayer::primitive2d::getB2DRangeFromPrimitive2DSequence( + rContent, + aViewInformation2D)); + + aClipPolyPolygon.transform( + basegfx::tools::createScaleTranslateB2DHomMatrix( + aContentRange.getRange(), + aContentRange.getMinimum())); + } + + // redefine target. Use MaskPrimitive2D with created clip + // geometry. Using the automatically set mbIsClipPathContent at + // SvgStyleAttributes the clip definition is without fill, stroke, + // and strokeWidth and forced to black + const drawinglayer::primitive2d::Primitive2DReference xEmbedTransparence( + new drawinglayer::primitive2d::MaskPrimitive2D( + aClipPolyPolygon, + rContent)); + + rContent = drawinglayer::primitive2d::Primitive2DSequence(&xEmbedTransparence, 1); + } + else + { + // An empty clipping path will completely clip away the element that had + // the clip-path property applied. (Svg spec) + rContent.realloc(0); + } + } + } + + } // end of namespace svgreader +} // end of namespace svgio + +////////////////////////////////////////////////////////////////////////////// +// eof + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svgio/source/svgreader/svgdocument.cxx b/svgio/source/svgreader/svgdocument.cxx new file mode 100644 index 000000000000..e5dd4acb5db2 --- /dev/null +++ b/svgio/source/svgreader/svgdocument.cxx @@ -0,0 +1,118 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <svgio/svgreader/svgdocument.hxx> + +////////////////////////////////////////////////////////////////////////////// + +namespace svgio +{ + namespace svgreader + { + SvgDocument::SvgDocument(const rtl::OUString& rAbsolutePath) + : maNodes(), + maAbsolutePath(rAbsolutePath), + maIdTokenMapperList(), + maIdStyleTokenMapperList() + { + } + + SvgDocument::~SvgDocument() + { + while(!maNodes.empty()) + { + SvgNode* pCandidate = maNodes[maNodes.size() - 1]; + delete pCandidate; + maNodes.pop_back(); + } + } + + void SvgDocument::appendNode(SvgNode* pNode) + { + OSL_ENSURE(pNode, "OOps, empty node added (!)"); + maNodes.push_back(pNode); + } + + void SvgDocument::addSvgNodeToMapper(const rtl::OUString& rStr, const SvgNode& rNode) + { + if(rStr.getLength()) + { + maIdTokenMapperList.insert(IdTokenValueType(rStr, &rNode)); + } + } + + void SvgDocument::removeSvgNodeFromMapper(const rtl::OUString& rStr) + { + if(rStr.getLength()) + { + maIdTokenMapperList.erase(rStr); + } + } + + const SvgNode* SvgDocument::findSvgNodeById(const rtl::OUString& rStr) const + { + const IdTokenMapper::const_iterator aResult(maIdTokenMapperList.find(rStr)); + + if(aResult == maIdTokenMapperList.end()) + { + return 0; + } + else + { + return aResult->second; + } + } + + void SvgDocument::addSvgStyleAttributesToMapper(const rtl::OUString& rStr, const SvgStyleAttributes& rSvgStyleAttributes) + { + if(rStr.getLength()) + { + maIdStyleTokenMapperList.insert(IdStyleTokenValueType(rStr, &rSvgStyleAttributes)); + } + } + + void SvgDocument::removeSvgStyleAttributesFromMapper(const rtl::OUString& rStr) + { + if(rStr.getLength()) + { + maIdStyleTokenMapperList.erase(rStr); + } + } + + const SvgStyleAttributes* SvgDocument::findSvgStyleAttributesById(const rtl::OUString& rStr) const + { + const IdStyleTokenMapper::const_iterator aResult(maIdStyleTokenMapperList.find(rStr)); + + if(aResult == maIdStyleTokenMapperList.end()) + { + return 0; + } + else + { + return aResult->second; + } + } + + } // end of namespace svgreader +} // end of namespace svgio + +////////////////////////////////////////////////////////////////////////////// +// eof + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svgio/source/svgreader/svgdocumenthandler.cxx b/svgio/source/svgreader/svgdocumenthandler.cxx new file mode 100644 index 000000000000..7cb91a790051 --- /dev/null +++ b/svgio/source/svgreader/svgdocumenthandler.cxx @@ -0,0 +1,549 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <svgio/svgreader/svgdocumenthandler.hxx> +#include <svgio/svgreader/svgtoken.hxx> +#include <svgio/svgreader/svgsvgnode.hxx> +#include <svgio/svgreader/svggnode.hxx> +#include <svgio/svgreader/svgnode.hxx> +#include <svgio/svgreader/svgpathnode.hxx> +#include <svgio/svgreader/svgrectnode.hxx> +#include <svgio/svgreader/svggradientnode.hxx> +#include <svgio/svgreader/svggradientstopnode.hxx> +#include <svgio/svgreader/svgsymbolnode.hxx> +#include <svgio/svgreader/svgusenode.hxx> +#include <svgio/svgreader/svgcirclenode.hxx> +#include <svgio/svgreader/svgellipsenode.hxx> +#include <svgio/svgreader/svglinenode.hxx> +#include <svgio/svgreader/svgpolynode.hxx> +#include <svgio/svgreader/svgsymbolnode.hxx> +#include <svgio/svgreader/svgtextnode.hxx> +#include <svgio/svgreader/svgcharacternode.hxx> +#include <svgio/svgreader/svgtspannode.hxx> +#include <svgio/svgreader/svgtrefnode.hxx> +#include <svgio/svgreader/svgtextpathnode.hxx> +#include <svgio/svgreader/svgstylenode.hxx> +#include <svgio/svgreader/svgimagenode.hxx> +#include <svgio/svgreader/svgclippathnode.hxx> +#include <svgio/svgreader/svgmasknode.hxx> +#include <svgio/svgreader/svgmarkernode.hxx> +#include <svgio/svgreader/svgpatternnode.hxx> + +////////////////////////////////////////////////////////////////////////////// + +using namespace com::sun::star; + +////////////////////////////////////////////////////////////////////////////// + +namespace +{ + svgio::svgreader::SvgCharacterNode* whiteSpaceHandling(svgio::svgreader::SvgNode* pNode, svgio::svgreader::SvgCharacterNode* pLast) + { + if(pNode) + { + const svgio::svgreader::SvgNodeVector& rChilds = pNode->getChildren(); + const sal_uInt32 nCount(rChilds.size()); + + for(sal_uInt32 a(0); a < nCount; a++) + { + svgio::svgreader::SvgNode* pCandidate = rChilds[a]; + + if(pCandidate) + { + switch(pCandidate->getType()) + { + case svgio::svgreader::SVGTokenCharacter: + { + // clean whitespace in text span + svgio::svgreader::SvgCharacterNode* pCharNode = static_cast< svgio::svgreader::SvgCharacterNode* >(pCandidate); + pCharNode->whiteSpaceHandling(); + + // pCharNode may have lost all text. If that's the case, ignore + // as invalid character node + if(pCharNode->getText().getLength()) + { + if(pLast) + { + // add in-between whitespace (single space) to last + // known character node + pLast->addGap(); + } + + // remember new last corected character node + pLast = pCharNode; + } + break; + } + case svgio::svgreader::SVGTokenTspan: + case svgio::svgreader::SVGTokenTextPath: + case svgio::svgreader::SVGTokenTref: + { + // recursively clean whitespaces in subhierarchy + pLast = whiteSpaceHandling(pCandidate, pLast); + break; + } + default: + { + OSL_ENSURE(false, "Unexpected token inside SVGTokenText (!)"); + break; + } + } + } + } + } + + return pLast; + } +} + +////////////////////////////////////////////////////////////////////////////// + +namespace svgio +{ + namespace svgreader + { + SvgDocHdl::SvgDocHdl(const rtl::OUString& aAbsolutePath) + : maDocument(aAbsolutePath), + mpTarget(0), + maCssContents() + { + } + + SvgDocHdl::~SvgDocHdl() + { +#ifdef DBG_UTIL + if(mpTarget) + { + OSL_ENSURE(false, "SvgDocHdl destructed with active target (!)"); + delete mpTarget; + } + OSL_ENSURE(!maCssContents.size(), "SvgDocHdl destructed with active css style stack entry (!)"); +#endif + } + + void SvgDocHdl::startDocument( ) throw (xml::sax::SAXException, uno::RuntimeException) + { + OSL_ENSURE(!mpTarget, "Already a target at document start (!)"); + OSL_ENSURE(!maCssContents.size(), "SvgDocHdl startDocument with active css style stack entry (!)"); + } + + void SvgDocHdl::endDocument( ) throw (xml::sax::SAXException, uno::RuntimeException) + { + OSL_ENSURE(!mpTarget, "Still a target at document end (!)"); + OSL_ENSURE(!maCssContents.size(), "SvgDocHdl endDocument with active css style stack entry (!)"); + } + + void SvgDocHdl::startElement( const ::rtl::OUString& aName, const uno::Reference< xml::sax::XAttributeList >& xAttribs ) throw (xml::sax::SAXException, uno::RuntimeException) + { + if(aName.getLength()) + { + const SVGToken aSVGToken(StrToSVGToken(aName)); + + switch(aSVGToken) + { + /// structural elements + case SVGTokenSymbol: + { + /// new basic node for Symbol. Content gets scanned, but + /// will not be decomposed (see SvgNode::decomposeSvgNode and bReferenced) + mpTarget = new SvgSymbolNode(maDocument, mpTarget); + mpTarget->parseAttributes(xAttribs); + break; + } + case SVGTokenDefs: + case SVGTokenG: + { + /// new node for Defs/G + mpTarget = new SvgGNode(aSVGToken, maDocument, mpTarget); + mpTarget->parseAttributes(xAttribs); + break; + } + case SVGTokenSvg: + { + /// new node for Svg + mpTarget = new SvgSvgNode(maDocument, mpTarget); + mpTarget->parseAttributes(xAttribs); + break; + } + case SVGTokenUse: + { + /// new node for Use + mpTarget = new SvgUseNode(maDocument, mpTarget); + mpTarget->parseAttributes(xAttribs); + break; + } + + /// shape elements + case SVGTokenCircle: + { + /// new node for Circle + mpTarget = new SvgCircleNode(maDocument, mpTarget); + mpTarget->parseAttributes(xAttribs); + break; + } + case SVGTokenEllipse: + { + /// new node for Ellipse + mpTarget = new SvgEllipseNode(maDocument, mpTarget); + mpTarget->parseAttributes(xAttribs); + break; + } + case SVGTokenLine: + { + /// new node for Line + mpTarget = new SvgLineNode(maDocument, mpTarget); + mpTarget->parseAttributes(xAttribs); + break; + } + case SVGTokenPath: + { + /// new node for Path + mpTarget = new SvgPathNode(maDocument, mpTarget); + mpTarget->parseAttributes(xAttribs); + break; + } + case SVGTokenPolygon: + { + /// new node for Polygon + mpTarget = new SvgPolyNode(maDocument, mpTarget, false); + mpTarget->parseAttributes(xAttribs); + break; + } + case SVGTokenPolyline: + { + /// new node for Polyline + mpTarget = new SvgPolyNode(maDocument, mpTarget, true); + mpTarget->parseAttributes(xAttribs); + break; + } + case SVGTokenRect: + { + /// new node for Rect + mpTarget = new SvgRectNode(maDocument, mpTarget); + mpTarget->parseAttributes(xAttribs); + break; + } + case SVGTokenImage: + { + /// new node for Image + mpTarget = new SvgImageNode(maDocument, mpTarget); + mpTarget->parseAttributes(xAttribs); + break; + } + + /// gradients + case SVGTokenLinearGradient: + case SVGTokenRadialGradient: + { + mpTarget = new SvgGradientNode(aSVGToken, maDocument, mpTarget); + mpTarget->parseAttributes(xAttribs); + break; + } + + /// gradient stops + case SVGTokenStop: + { + mpTarget = new SvgGradientStopNode(maDocument, mpTarget); + mpTarget->parseAttributes(xAttribs); + break; + } + + /// text + case SVGTokenText: + { + mpTarget = new SvgTextNode(maDocument, mpTarget); + mpTarget->parseAttributes(xAttribs); + break; + } + case SVGTokenTspan: + { + mpTarget = new SvgTspanNode(maDocument, mpTarget); + mpTarget->parseAttributes(xAttribs); + break; + } + case SVGTokenTref: + { + mpTarget = new SvgTrefNode(maDocument, mpTarget); + mpTarget->parseAttributes(xAttribs); + break; + } + case SVGTokenTextPath: + { + mpTarget = new SvgTextPathNode(maDocument, mpTarget); + mpTarget->parseAttributes(xAttribs); + break; + } + + /// styles (as stylesheets) + case SVGTokenStyle: + { + SvgStyleNode* pNew = new SvgStyleNode(maDocument, mpTarget); + mpTarget = pNew; + mpTarget->parseAttributes(xAttribs); + + if(pNew->isTextCss()) + { + maCssContents.push_back(rtl::OUString()); + } + break; + } + + /// structural elements clip-path and mask. Content gets scanned, but + /// will not be decomposed (see SvgNode::decomposeSvgNode and bReferenced) + case SVGTokenClipPathNode: + { + /// new node for ClipPath + mpTarget = new SvgClipPathNode(maDocument, mpTarget); + mpTarget->parseAttributes(xAttribs); + break; + } + case SVGTokenMask: + { + /// new node for Mask + mpTarget = new SvgMaskNode(maDocument, mpTarget); + mpTarget->parseAttributes(xAttribs); + break; + } + + /// structural element marker + case SVGTokenMarker: + { + /// new node for marker + mpTarget = new SvgMarkerNode(maDocument, mpTarget); + mpTarget->parseAttributes(xAttribs); + break; + } + + /// structural element pattern + case SVGTokenPattern: + { + /// new node for pattern + mpTarget = new SvgPatternNode(maDocument, mpTarget); + mpTarget->parseAttributes(xAttribs); + break; + } + + default: + { + /// invalid token, ignore +#ifdef DBG_UTIL + myAssert( + rtl::OUString::createFromAscii("Unknown Base SvgToken <") + + aName + + rtl::OUString::createFromAscii("> (!)")); +#endif + break; + } + } + } + } + + void SvgDocHdl::endElement( const ::rtl::OUString& aName ) throw (xml::sax::SAXException, uno::RuntimeException) + { + if(aName.getLength()) + { + const SVGToken aSVGToken(StrToSVGToken(aName)); + SvgNode* pWhitespaceCheck(SVGTokenText == aSVGToken ? mpTarget : 0); + SvgStyleNode* pCssStyle(SVGTokenStyle == aSVGToken ? static_cast< SvgStyleNode* >(mpTarget) : 0); + + switch(aSVGToken) + { + /// valid tokens for which a new one was created + + /// structural elements + case SVGTokenDefs: + case SVGTokenG: + case SVGTokenSvg: + case SVGTokenSymbol: + case SVGTokenUse: + + /// shape elements + case SVGTokenCircle: + case SVGTokenEllipse: + case SVGTokenLine: + case SVGTokenPath: + case SVGTokenPolygon: + case SVGTokenPolyline: + case SVGTokenRect: + case SVGTokenImage: + + /// gradients + case SVGTokenLinearGradient: + case SVGTokenRadialGradient: + + /// gradient stops + case SVGTokenStop: + + /// text + case SVGTokenText: + case SVGTokenTspan: + case SVGTokenTextPath: + case SVGTokenTref: + + /// styles (as stylesheets) + case SVGTokenStyle: + + /// structural elements clip-path and mask + case SVGTokenClipPathNode: + case SVGTokenMask: + + /// structural element marker + case SVGTokenMarker: + + /// structural element pattern + case SVGTokenPattern: + + /// content handling after parsing + { + if(mpTarget) + { + if(!mpTarget->getParent()) + { + // last element closing, save this tree + maDocument.appendNode(mpTarget); + } + + mpTarget = const_cast< SvgNode* >(mpTarget->getParent()); + } + else + { + OSL_ENSURE(false, "Closing token, but no context (!)"); + } + break; + } + default: + { + /// invalid token, ignore + } + } + + if(pCssStyle && pCssStyle->isTextCss()) + { + // css style parsing + if(maCssContents.size()) + { + // need to interpret css styles and remember them as StyleSheets + pCssStyle->addCssStyleSheet(*(maCssContents.end() - 1)); + maCssContents.pop_back(); + } + else + { + OSL_ENSURE(false, "Closing CssStyle, but no collector string on stack (!)"); + } + } + + if(pWhitespaceCheck) + { + // cleanup read strings + whiteSpaceHandling(pWhitespaceCheck, 0); + } + } + } + + void SvgDocHdl::characters( const ::rtl::OUString& aChars ) throw (xml::sax::SAXException, uno::RuntimeException) + { + if(mpTarget) + { + const sal_uInt32 nLength(aChars.getLength()); + + if(nLength && + (SVGTokenText == mpTarget->getType() || + SVGTokenTspan == mpTarget->getType() || + SVGTokenTextPath == mpTarget->getType() || + SVGTokenStyle == mpTarget->getType())) + { + switch(mpTarget->getType()) + { + case SVGTokenText: + case SVGTokenTspan: + case SVGTokenTextPath: + { + const SvgNodeVector& rChilds = mpTarget->getChildren(); + SvgCharacterNode* pTarget = 0; + + if(rChilds.size()) + { + pTarget = dynamic_cast< SvgCharacterNode* >(rChilds[rChilds.size() - 1]); + } + + if(pTarget) + { + // concatenate to current character span + pTarget->concatenate(aChars); + } + else + { + // add character span as simplified tspan (no arguments) + // as direct child of SvgTextNode/SvgTspanNode/SvgTextPathNode + new SvgCharacterNode(maDocument, mpTarget, aChars); + } + break; + } + case SVGTokenStyle: + { + SvgStyleNode& rSvgStyleNode = static_cast< SvgStyleNode& >(*mpTarget); + + if(rSvgStyleNode.isTextCss()) + { + // collect characters for css style + if(maCssContents.size()) + { + const ::rtl::OUString aTrimmedChars(aChars.trim()); + + if(aTrimmedChars.getLength()) + { + std::vector< rtl::OUString >::iterator aString(maCssContents.end() - 1); + (*aString) += aTrimmedChars; + } + } + else + { + OSL_ENSURE(false, "Closing CssStyle, but no collector string on stack (!)"); + } + } + break; + } + default: + { + // characters not used by a known node + break; + } + } + } + } + } + + void SvgDocHdl::ignorableWhitespace(const ::rtl::OUString& /*aWhitespaces*/) throw (xml::sax::SAXException, uno::RuntimeException) + { + } + + void SvgDocHdl::processingInstruction(const ::rtl::OUString& /*aTarget*/, const ::rtl::OUString& /*aData*/) throw (xml::sax::SAXException, uno::RuntimeException) + { + } + + void SvgDocHdl::setDocumentLocator(const uno::Reference< xml::sax::XLocator >& /*xLocator*/) throw (xml::sax::SAXException, uno::RuntimeException) + { + } + } // end of namespace svgreader +} // end of namespace svgio + +////////////////////////////////////////////////////////////////////////////// +// eof + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svgio/source/svgreader/svgellipsenode.cxx b/svgio/source/svgreader/svgellipsenode.cxx new file mode 100644 index 000000000000..f34edb244f4a --- /dev/null +++ b/svgio/source/svgreader/svgellipsenode.cxx @@ -0,0 +1,170 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <svgio/svgreader/svgellipsenode.hxx> +#include <basegfx/polygon/b2dpolygon.hxx> +#include <basegfx/polygon/b2dpolygontools.hxx> + +////////////////////////////////////////////////////////////////////////////// + +namespace svgio +{ + namespace svgreader + { + SvgEllipseNode::SvgEllipseNode( + SvgDocument& rDocument, + SvgNode* pParent) + : SvgNode(SVGTokenEllipse, rDocument, pParent), + maSvgStyleAttributes(*this), + maCx(0), + maCy(0), + maRx(0), + maRy(0), + mpaTransform(0) + { + } + + SvgEllipseNode::~SvgEllipseNode() + { + if(mpaTransform) delete mpaTransform; + } + + const SvgStyleAttributes* SvgEllipseNode::getSvgStyleAttributes() const + { + static rtl::OUString aClassStr(rtl::OUString::createFromAscii("ellipse")); + maSvgStyleAttributes.checkForCssStyle(aClassStr); + + return &maSvgStyleAttributes; + } + + void SvgEllipseNode::parseAttribute(const rtl::OUString& rTokenName, SVGToken aSVGToken, const rtl::OUString& aContent) + { + // call parent + SvgNode::parseAttribute(rTokenName, aSVGToken, aContent); + + // read style attributes + maSvgStyleAttributes.parseStyleAttribute(rTokenName, aSVGToken, aContent); + + // parse own + switch(aSVGToken) + { + case SVGTokenStyle: + { + maSvgStyleAttributes.readStyle(aContent); + break; + } + case SVGTokenCx: + { + SvgNumber aNum; + + if(readSingleNumber(aContent, aNum)) + { + setCx(aNum); + } + break; + } + case SVGTokenCy: + { + SvgNumber aNum; + + if(readSingleNumber(aContent, aNum)) + { + setCy(aNum); + } + break; + } + case SVGTokenRx: + { + SvgNumber aNum; + + if(readSingleNumber(aContent, aNum)) + { + if(aNum.isPositive()) + { + setRx(aNum); + } + } + break; + } + case SVGTokenRy: + { + SvgNumber aNum; + + if(readSingleNumber(aContent, aNum)) + { + if(aNum.isPositive()) + { + setRy(aNum); + } + } + break; + } + case SVGTokenTransform: + { + const basegfx::B2DHomMatrix aMatrix(readTransform(aContent, *this)); + + if(!aMatrix.isIdentity()) + { + setTransform(&aMatrix); + } + break; + } + default: + { + break; + } + } + } + + void SvgEllipseNode::decomposeSvgNode(drawinglayer::primitive2d::Primitive2DSequence& rTarget, bool /*bReferenced*/) const + { + const SvgStyleAttributes* pStyle = getSvgStyleAttributes(); + + if(pStyle && getRx().isSet() && getRy().isSet()) + { + const double fRx(getRx().solve(*this, xcoordinate)); + const double fRy(getRy().solve(*this, ycoordinate)); + + if(fRx > 0.0 && fRy > 0.0) + { + const basegfx::B2DPolygon aPath( + basegfx::tools::createPolygonFromEllipse( + basegfx::B2DPoint( + getCx().isSet() ? getCx().solve(*this, xcoordinate) : 0.0, + getCy().isSet() ? getCy().solve(*this, ycoordinate) : 0.0), + fRx, fRy)); + + drawinglayer::primitive2d::Primitive2DSequence aNewTarget; + + pStyle->add_path(basegfx::B2DPolyPolygon(aPath), aNewTarget); + + if(aNewTarget.hasElements()) + { + pStyle->add_postProcess(rTarget, aNewTarget, getTransform()); + } + } + } + } + } // end of namespace svgreader +} // end of namespace svgio + +////////////////////////////////////////////////////////////////////////////// +// eof + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svgio/source/svgreader/svggnode.cxx b/svgio/source/svgreader/svggnode.cxx new file mode 100644 index 000000000000..df2ad5aed125 --- /dev/null +++ b/svgio/source/svgreader/svggnode.cxx @@ -0,0 +1,115 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <svgio/svgreader/svggnode.hxx> +#include <drawinglayer/primitive2d/transformprimitive2d.hxx> +#include <drawinglayer/primitive2d/unifiedtransparenceprimitive2d.hxx> + +////////////////////////////////////////////////////////////////////////////// + +namespace svgio +{ + namespace svgreader + { + SvgGNode::SvgGNode( + SVGToken aType, + SvgDocument& rDocument, + SvgNode* pParent) + : SvgNode(aType, rDocument, pParent), + maSvgStyleAttributes(*this), + mpaTransform(0) + { + OSL_ENSURE(aType == SVGTokenDefs || aType == SVGTokenG, "SvgGNode should ony be used for Group and Defs (!)"); + } + + SvgGNode::~SvgGNode() + { + if(mpaTransform) delete mpaTransform; + } + + const SvgStyleAttributes* SvgGNode::getSvgStyleAttributes() const + { + static rtl::OUString aClassStr(rtl::OUString::createFromAscii("g")); + maSvgStyleAttributes.checkForCssStyle(aClassStr); + + return &maSvgStyleAttributes; + } + + void SvgGNode::parseAttribute(const rtl::OUString& rTokenName, SVGToken aSVGToken, const rtl::OUString& aContent) + { + // call parent + SvgNode::parseAttribute(rTokenName, aSVGToken, aContent); + + // read style attributes + maSvgStyleAttributes.parseStyleAttribute(rTokenName, aSVGToken, aContent); + + // parse own + switch(aSVGToken) + { + case SVGTokenStyle: + { + maSvgStyleAttributes.readStyle(aContent); + break; + } + case SVGTokenTransform: + { + const basegfx::B2DHomMatrix aMatrix(readTransform(aContent, *this)); + + if(!aMatrix.isIdentity()) + { + setTransform(&aMatrix); + } + break; + } + default: + { + break; + } + } + } + + void SvgGNode::decomposeSvgNode(drawinglayer::primitive2d::Primitive2DSequence& rTarget, bool bReferenced) const + { + const SvgStyleAttributes* pStyle = getSvgStyleAttributes(); + + if(pStyle) + { + const double fOpacity(pStyle->getOpacity().getNumber()); + + if(fOpacity > 0.0) + { + drawinglayer::primitive2d::Primitive2DSequence aContent; + + // decompose childs + SvgNode::decomposeSvgNode(aContent, bReferenced); + + if(aContent.hasElements()) + { + pStyle->add_postProcess(rTarget, aContent, getTransform()); + } + } + } + } + } // end of namespace svgreader +} // end of namespace svgio + +////////////////////////////////////////////////////////////////////////////// +// eof + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svgio/source/svgreader/svggradientnode.cxx b/svgio/source/svgreader/svggradientnode.cxx new file mode 100644 index 000000000000..74878d1ecb9e --- /dev/null +++ b/svgio/source/svgreader/svggradientnode.cxx @@ -0,0 +1,508 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <svgio/svgreader/svggradientnode.hxx> +#include <svgio/svgreader/svgdocument.hxx> +#include <svgio/svgreader/svggradientstopnode.hxx> + +////////////////////////////////////////////////////////////////////////////// + +namespace svgio +{ + namespace svgreader + { + void SvgGradientNode::tryToFindLink() + { + if(!mpXLink && maXLink.getLength()) + { + mpXLink = dynamic_cast< const SvgGradientNode* >(getDocument().findSvgNodeById(maXLink)); + } + } + + SvgGradientNode::SvgGradientNode( + SVGToken aType, + SvgDocument& rDocument, + SvgNode* pParent) + : SvgNode(aType, rDocument, pParent), + maSvgStyleAttributes(*this), + maX1(), + maY1(), + maX2(), + maY2(), + maCx(), + maCy(), + maR(), + maFx(), + maFy(), + maGradientUnits(objectBoundingBox), + maSpreadMethod(drawinglayer::primitive2d::Spread_pad), + mpaGradientTransform(0), + maXLink(), + mpXLink(0) + { + } + + SvgGradientNode::~SvgGradientNode() + { + if(mpaGradientTransform) delete mpaGradientTransform; + // do NOT delete mpXLink, it's only referenced, not owned + } + + const SvgStyleAttributes* SvgGradientNode::getSvgStyleAttributes() const + { + return &maSvgStyleAttributes; + } + + void SvgGradientNode::parseAttribute(const rtl::OUString& rTokenName, SVGToken aSVGToken, const rtl::OUString& aContent) + { + // call parent + SvgNode::parseAttribute(rTokenName, aSVGToken, aContent); + + // read style attributes + maSvgStyleAttributes.parseStyleAttribute(rTokenName, aSVGToken, aContent); + + // parse own + switch(aSVGToken) + { + case SVGTokenStyle: + { + maSvgStyleAttributes.readStyle(aContent); + break; + } + case SVGTokenX1: + { + SvgNumber aNum; + + if(readSingleNumber(aContent, aNum)) + { + setX1(aNum); + } + break; + } + case SVGTokenY1: + { + SvgNumber aNum; + + if(readSingleNumber(aContent, aNum)) + { + setY1(aNum); + } + break; + } + case SVGTokenX2: + { + SvgNumber aNum; + + if(readSingleNumber(aContent, aNum)) + { + setX2(aNum); + } + break; + } + case SVGTokenY2: + { + SvgNumber aNum; + + if(readSingleNumber(aContent, aNum)) + { + setY2(aNum); + } + break; + } + case SVGTokenCx: + { + SvgNumber aNum; + + if(readSingleNumber(aContent, aNum)) + { + setCx(aNum); + } + break; + } + case SVGTokenCy: + { + SvgNumber aNum; + + if(readSingleNumber(aContent, aNum)) + { + setCy(aNum); + } + break; + } + case SVGTokenFx: + { + SvgNumber aNum; + + if(readSingleNumber(aContent, aNum)) + { + setFx(aNum); + } + break; + } + case SVGTokenFy: + { + SvgNumber aNum; + + if(readSingleNumber(aContent, aNum)) + { + setFy(aNum); + } + break; + } + case SVGTokenR: + { + SvgNumber aNum; + + if(readSingleNumber(aContent, aNum)) + { + if(aNum.isPositive()) + { + setR(aNum); + } + } + break; + } + case SVGTokenGradientUnits: + { + if(aContent.getLength()) + { + if(aContent.match(commonStrings::aStrUserSpaceOnUse, 0)) + { + setGradientUnits(userSpaceOnUse); + } + else if(aContent.match(commonStrings::aStrObjectBoundingBox, 0)) + { + setGradientUnits(objectBoundingBox); + } + } + break; + } + case SVGTokenSpreadMethod: + { + if(aContent.getLength()) + { + static rtl::OUString aStrPad(rtl::OUString::createFromAscii("pad")); + static rtl::OUString aStrReflect(rtl::OUString::createFromAscii("reflect")); + static rtl::OUString aStrRepeat(rtl::OUString::createFromAscii("repeat")); + + if(aContent.match(aStrPad, 0)) + { + setSpreadMethod(drawinglayer::primitive2d::Spread_pad); + } + else if(aContent.match(aStrReflect, 0)) + { + setSpreadMethod(drawinglayer::primitive2d::Spread_reflect); + } + else if(aContent.match(aStrRepeat, 0)) + { + setSpreadMethod(drawinglayer::primitive2d::Spread_repeat); + } + } + break; + } + case SVGTokenGradientTransform: + { + const basegfx::B2DHomMatrix aMatrix(readTransform(aContent, *this)); + + if(!aMatrix.isIdentity()) + { + setGradientTransform(&aMatrix); + } + break; + } + case SVGTokenXlinkHref: + { + const sal_Int32 nLen(aContent.getLength()); + + if(nLen && sal_Unicode('#') == aContent[0]) + { + maXLink = aContent.copy(1); + tryToFindLink(); + } + break; + } + default: + { + break; + } + } + } + + void SvgGradientNode::collectGradientEntries(drawinglayer::primitive2d::SvgGradientEntryVector& aVector) const + { + if(getChildren().empty()) + { + const_cast< SvgGradientNode* >(this)->tryToFindLink(); + + if(mpXLink) + { + mpXLink->collectGradientEntries(aVector); + } + } + else + { + const sal_uInt32 nCount(getChildren().size()); + + for(sal_uInt32 a(0); a < nCount; a++) + { + const SvgGradientStopNode* pCandidate = dynamic_cast< const SvgGradientStopNode* >(getChildren()[a]); + + if(pCandidate) + { + const SvgStyleAttributes* pStyle = pCandidate->getSvgStyleAttributes(); + + if(pStyle) + { + const SvgNumber aOffset(pCandidate->getOffset()); + double fOffset(0.0); + + if(Unit_percent == aOffset.getUnit()) + { + // percent is not relative to distances in ColorStop context, solve locally + fOffset = aOffset.getNumber() * 0.01; + } + else + { + fOffset = aOffset.solve(*this); + } + + if(fOffset < 0.0) + { + OSL_ENSURE(false, "OOps, SvgGradientStopNode with offset out of range (!)"); + fOffset = 0.0; + } + else if(fOffset > 1.0) + { + OSL_ENSURE(false, "OOps, SvgGradientStopNode with offset out of range (!)"); + fOffset = 1.0; + } + + aVector.push_back( + drawinglayer::primitive2d::SvgGradientEntry( + fOffset, + pStyle->getStopColor(), + pStyle->getStopOpacity().solve(*this))); + } + else + { + OSL_ENSURE(false, "OOps, SvgGradientStopNode without Style (!)"); + } + } + } + } + } + + const SvgNumber SvgGradientNode::getX1() const + { + if(maX1.isSet()) + { + return maX1; + } + + const_cast< SvgGradientNode* >(this)->tryToFindLink(); + + if(mpXLink) + { + return mpXLink->getX1(); + } + + // default is 0% + return SvgNumber(0.0, Unit_percent); + } + + const SvgNumber SvgGradientNode::getY1() const + { + if(maY1.isSet()) + { + return maY1; + } + + const_cast< SvgGradientNode* >(this)->tryToFindLink(); + + if(mpXLink) + { + return mpXLink->getY1(); + } + + // default is 0% + return SvgNumber(0.0, Unit_percent); + } + + const SvgNumber SvgGradientNode::getX2() const + { + if(maX2.isSet()) + { + return maX2; + } + + const_cast< SvgGradientNode* >(this)->tryToFindLink(); + + if(mpXLink) + { + return mpXLink->getX2(); + } + + // default is 100% + return SvgNumber(100.0, Unit_percent); + } + + const SvgNumber SvgGradientNode::getY2() const + { + if(maY2.isSet()) + { + return maY2; + } + + const_cast< SvgGradientNode* >(this)->tryToFindLink(); + + if(mpXLink) + { + return mpXLink->getY2(); + } + + // default is 0% + return SvgNumber(0.0, Unit_percent); + } + + const SvgNumber SvgGradientNode::getCx() const + { + if(maCx.isSet()) + { + return maCx; + } + + const_cast< SvgGradientNode* >(this)->tryToFindLink(); + + if(mpXLink) + { + return mpXLink->getCx(); + } + + // default is 50% + return SvgNumber(50.0, Unit_percent); + } + + const SvgNumber SvgGradientNode::getCy() const + { + if(maCy.isSet()) + { + return maCy; + } + + const_cast< SvgGradientNode* >(this)->tryToFindLink(); + + if(mpXLink) + { + return mpXLink->getCy(); + } + + // default is 50% + return SvgNumber(50.0, Unit_percent); + } + + const SvgNumber SvgGradientNode::getR() const + { + if(maR.isSet()) + { + return maR; + } + + const_cast< SvgGradientNode* >(this)->tryToFindLink(); + + if(mpXLink) + { + return mpXLink->getR(); + } + + // default is 50% + return SvgNumber(50.0, Unit_percent); + } + + const SvgNumber* SvgGradientNode::getFx() const + { + if(maFx.isSet()) + { + return &maFx; + } + + const_cast< SvgGradientNode* >(this)->tryToFindLink(); + + if(mpXLink) + { + return mpXLink->getFx(); + } + + return 0; + } + + const SvgNumber* SvgGradientNode::getFy() const + { + if(maFy.isSet()) + { + return &maFy; + } + + const_cast< SvgGradientNode* >(this)->tryToFindLink(); + + if(mpXLink) + { + return mpXLink->getFy(); + } + + return 0; + } + + const basegfx::B2DHomMatrix* SvgGradientNode::getGradientTransform() const + { + if(mpaGradientTransform) + { + return mpaGradientTransform; + } + + const_cast< SvgGradientNode* >(this)->tryToFindLink(); + + if(mpXLink) + { + return mpXLink->getGradientTransform(); + } + + return 0; + } + + void SvgGradientNode::setGradientTransform(const basegfx::B2DHomMatrix* pMatrix) + { + if(mpaGradientTransform) + { + delete mpaGradientTransform; + mpaGradientTransform = 0; + } + + if(pMatrix) + { + mpaGradientTransform = new basegfx::B2DHomMatrix(*pMatrix); + } + } + + } // end of namespace svgreader +} // end of namespace svgio + +////////////////////////////////////////////////////////////////////////////// +// eof + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svgio/source/svgreader/svggradientstopnode.cxx b/svgio/source/svgreader/svggradientstopnode.cxx new file mode 100644 index 000000000000..cf9b069395d5 --- /dev/null +++ b/svgio/source/svgreader/svggradientstopnode.cxx @@ -0,0 +1,88 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <svgio/svgreader/svggradientstopnode.hxx> + +////////////////////////////////////////////////////////////////////////////// + +namespace svgio +{ + namespace svgreader + { + SvgGradientStopNode::SvgGradientStopNode( + SvgDocument& rDocument, + SvgNode* pParent) + : SvgNode(SVGTokenStop, rDocument, pParent), + maSvgStyleAttributes(*this), + maOffset() + { + } + + SvgGradientStopNode::~SvgGradientStopNode() + { + } + + const SvgStyleAttributes* SvgGradientStopNode::getSvgStyleAttributes() const + { + return &maSvgStyleAttributes; + } + + void SvgGradientStopNode::parseAttribute(const rtl::OUString& rTokenName, SVGToken aSVGToken, const rtl::OUString& aContent) + { + // call parent + SvgNode::parseAttribute(rTokenName, aSVGToken, aContent); + + // read style attributes + maSvgStyleAttributes.parseStyleAttribute(rTokenName, aSVGToken, aContent); + + // parse own + switch(aSVGToken) + { + case SVGTokenStyle: + { + maSvgStyleAttributes.readStyle(aContent); + break; + } + case SVGTokenOffset: + { + SvgNumber aNum; + + if(readSingleNumber(aContent, aNum)) + { + if(aNum.isPositive()) + { + setOffset(aNum); + } + } + break; + } + default: + { + break; + } + } + } + + } // end of namespace svgreader +} // end of namespace svgio + +////////////////////////////////////////////////////////////////////////////// +// eof + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svgio/source/svgreader/svgimagenode.cxx b/svgio/source/svgreader/svgimagenode.cxx new file mode 100644 index 000000000000..b57bf800c29e --- /dev/null +++ b/svgio/source/svgreader/svgimagenode.cxx @@ -0,0 +1,354 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <svgio/svgreader/svgimagenode.hxx> +#include <svgio/svgreader/svgdocument.hxx> +#include <sax/tools/converter.hxx> +#include <tools/stream.hxx> +#include <vcl/bitmapex.hxx> +#include <svtools/filter.hxx> +#include <basegfx/matrix/b2dhommatrixtools.hxx> +#include <drawinglayer/primitive2d/bitmapprimitive2d.hxx> +#include <drawinglayer/primitive2d/groupprimitive2d.hxx> +#include <drawinglayer/primitive2d/transformprimitive2d.hxx> +#include <drawinglayer/primitive2d/maskprimitive2d.hxx> +#include <basegfx/polygon/b2dpolygontools.hxx> +#include <basegfx/polygon/b2dpolygon.hxx> +#include <rtl/uri.hxx> +#include <drawinglayer/geometry/viewinformation2d.hxx> + +////////////////////////////////////////////////////////////////////////////// + +namespace svgio +{ + namespace svgreader + { + SvgImageNode::SvgImageNode( + SvgDocument& rDocument, + SvgNode* pParent) + : SvgNode(SVGTokenRect, rDocument, pParent), + maSvgStyleAttributes(*this), + maSvgAspectRatio(), + mpaTransform(0), + maX(0), + maY(0), + maWidth(0), + maHeight(0), + maXLink(), + maUrl(), + maMimeType(), + maData() + { + } + + SvgImageNode::~SvgImageNode() + { + if(mpaTransform) delete mpaTransform; + } + + const SvgStyleAttributes* SvgImageNode::getSvgStyleAttributes() const + { + static rtl::OUString aClassStr(rtl::OUString::createFromAscii("image")); + maSvgStyleAttributes.checkForCssStyle(aClassStr); + + return &maSvgStyleAttributes; + } + + void SvgImageNode::parseAttribute(const rtl::OUString& rTokenName, SVGToken aSVGToken, const rtl::OUString& aContent) + { + // call parent + SvgNode::parseAttribute(rTokenName, aSVGToken, aContent); + + // read style attributes + maSvgStyleAttributes.parseStyleAttribute(rTokenName, aSVGToken, aContent); + + // parse own + switch(aSVGToken) + { + case SVGTokenStyle: + { + maSvgStyleAttributes.readStyle(aContent); + break; + } + case SVGTokenPreserveAspectRatio: + { + setSvgAspectRatio(readSvgAspectRatio(aContent)); + break; + } + case SVGTokenTransform: + { + const basegfx::B2DHomMatrix aMatrix(readTransform(aContent, *this)); + + if(!aMatrix.isIdentity()) + { + setTransform(&aMatrix); + } + break; + } + case SVGTokenX: + { + SvgNumber aNum; + + if(readSingleNumber(aContent, aNum)) + { + setX(aNum); + } + break; + } + case SVGTokenY: + { + SvgNumber aNum; + + if(readSingleNumber(aContent, aNum)) + { + setY(aNum); + } + break; + } + case SVGTokenWidth: + { + SvgNumber aNum; + + if(readSingleNumber(aContent, aNum)) + { + if(aNum.isPositive()) + { + setWidth(aNum); + } + } + break; + } + case SVGTokenHeight: + { + SvgNumber aNum; + + if(readSingleNumber(aContent, aNum)) + { + if(aNum.isPositive()) + { + setHeight(aNum); + } + } + break; + } + case SVGTokenXlinkHref: + { + const sal_Int32 nLen(aContent.getLength()); + + if(nLen) + { + readImageLink(aContent, maXLink, maUrl, maMimeType, maData); + } + break; + } + default: + { + break; + } + } + } + + void extractFromGraphic( + const Graphic& rGraphic, + drawinglayer::primitive2d::Primitive2DSequence& rEmbedded, + basegfx::B2DRange& rViewBox, + BitmapEx& rBitmapEx) + { + if(GRAPHIC_BITMAP == rGraphic.GetType()) + { + if(rGraphic.getSvgData().get()) + { + // embedded Svg + rEmbedded = rGraphic.getSvgData()->getPrimitive2DSequence(); + + // fill aViewBox + rViewBox = rGraphic.getSvgData()->getRange(); + } + else + { + // get bitmap + rBitmapEx = rGraphic.GetBitmapEx(); + } + } + else + { + // evtl. convert to bitmap + rBitmapEx = rGraphic.GetBitmapEx(); + } + } + + void SvgImageNode::decomposeSvgNode(drawinglayer::primitive2d::Primitive2DSequence& rTarget, bool /*bReferenced*/) const + { + // get size range and create path + const SvgStyleAttributes* pStyle = getSvgStyleAttributes(); + + if(pStyle && getWidth().isSet() && getHeight().isSet()) + { + const double fWidth(getWidth().solve(*this, xcoordinate)); + const double fHeight(getHeight().solve(*this, ycoordinate)); + + if(fWidth > 0.0 && fHeight > 0.0) + { + BitmapEx aBitmapEx; + drawinglayer::primitive2d::Primitive2DSequence aNewTarget; + + // prepare Target and ViewBox for evtl. AspectRatio mappings + const double fX(getX().isSet() ? getX().solve(*this, xcoordinate) : 0.0); + const double fY(getY().isSet() ? getY().solve(*this, ycoordinate) : 0.0); + const basegfx::B2DRange aTarget(fX, fY, fX + fWidth, fY + fHeight); + basegfx::B2DRange aViewBox(aTarget); + + if(maMimeType.getLength() && maData.getLength()) + { + // use embedded base64 encoded data + ::com::sun::star::uno::Sequence< sal_Int8 > aPass; + ::sax::Converter::decodeBase64(aPass, maData); + + if(aPass.hasElements()) + { + SvMemoryStream aStream(aPass.getArray(), aPass.getLength(), STREAM_READ); + Graphic aGraphic; + + if(GRFILTER_OK == GraphicFilter::GetGraphicFilter().ImportGraphic( + aGraphic, + String(), + aStream)) + { + extractFromGraphic(aGraphic, aNewTarget, aViewBox, aBitmapEx); + } + } + } + else if(maUrl.getLength()) + { + const rtl::OUString& rPath = getDocument().getAbsolutePath(); + const rtl::OUString aAbsUrl(rtl::Uri::convertRelToAbs(rPath, maUrl)); + + if(aAbsUrl.getLength()) + { + SvFileStream aStream(aAbsUrl, STREAM_STD_READ); + Graphic aGraphic; + + if(GRFILTER_OK == GraphicFilter::GetGraphicFilter().ImportGraphic( + aGraphic, + aAbsUrl, + aStream)) + { + extractFromGraphic(aGraphic, aNewTarget, aViewBox, aBitmapEx); + } + } + } + else if(maXLink.getLength()) + { + const SvgNode* mpXLink = getDocument().findSvgNodeById(maXLink); + + if(mpXLink) + { + mpXLink->decomposeSvgNode(aNewTarget, true); + + if(aNewTarget.hasElements()) + { + aViewBox = drawinglayer::primitive2d::getB2DRangeFromPrimitive2DSequence( + aNewTarget, + drawinglayer::geometry::ViewInformation2D()); + } + } + } + + if(!aBitmapEx.IsEmpty()) + { + // create content from created bitmap + aNewTarget.realloc(1); + aNewTarget[0] = new drawinglayer::primitive2d::BitmapPrimitive2D( + aBitmapEx, + basegfx::B2DHomMatrix()); + + // fill aViewBox. No size set yet, use unit size + aViewBox = basegfx::B2DRange(0.0, 0.0, 1.0, 1.0); + } + + if(aNewTarget.hasElements()) + { + if(aTarget.equal(aViewBox)) + { + // just add to rTarget + drawinglayer::primitive2d::appendPrimitive2DSequenceToPrimitive2DSequence(rTarget, aNewTarget); + } + else + { + // create mapping + const SvgAspectRatio& rRatio = getSvgAspectRatio(); + + if(rRatio.isSet()) + { + // let mapping be created from SvgAspectRatio + const basegfx::B2DHomMatrix aEmbeddingTransform(rRatio.createMapping(aTarget, aViewBox)); + + if(!aEmbeddingTransform.isIdentity()) + { + const drawinglayer::primitive2d::Primitive2DReference xRef( + new drawinglayer::primitive2d::TransformPrimitive2D( + aEmbeddingTransform, + aNewTarget)); + + aNewTarget = drawinglayer::primitive2d::Primitive2DSequence(&xRef, 1); + } + + if(!rRatio.isMeetOrSlice()) + { + // need to embed in MaskPrimitive2D to ensure clipping + const drawinglayer::primitive2d::Primitive2DReference xMask( + new drawinglayer::primitive2d::MaskPrimitive2D( + basegfx::B2DPolyPolygon( + basegfx::tools::createPolygonFromRect(aTarget)), + aNewTarget)); + + aNewTarget = drawinglayer::primitive2d::Primitive2DSequence(&xMask, 1); + } + } + else + { + // choose default mapping + const basegfx::B2DHomMatrix aEmbeddingTransform(rRatio.createLinearMapping(aTarget, aViewBox)); + + if(!aEmbeddingTransform.isIdentity()) + { + const drawinglayer::primitive2d::Primitive2DReference xRef( + new drawinglayer::primitive2d::TransformPrimitive2D( + aEmbeddingTransform, + aNewTarget)); + + aNewTarget = drawinglayer::primitive2d::Primitive2DSequence(&xRef, 1); + } + } + + // embed and add to rTarget, take local extra-transform into account + pStyle->add_postProcess(rTarget, aNewTarget, getTransform()); + } + } + } + } + } + + } // end of namespace svgreader +} // end of namespace svgio + +////////////////////////////////////////////////////////////////////////////// +// eof + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svgio/source/svgreader/svglinenode.cxx b/svgio/source/svgreader/svglinenode.cxx new file mode 100644 index 000000000000..bd8ad988635c --- /dev/null +++ b/svgio/source/svgreader/svglinenode.cxx @@ -0,0 +1,166 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <svgio/svgreader/svglinenode.hxx> +#include <basegfx/polygon/b2dpolygon.hxx> +#include <basegfx/polygon/b2dpolygontools.hxx> + +////////////////////////////////////////////////////////////////////////////// + +namespace svgio +{ + namespace svgreader + { + SvgLineNode::SvgLineNode( + SvgDocument& rDocument, + SvgNode* pParent) + : SvgNode(SVGTokenLine, rDocument, pParent), + maSvgStyleAttributes(*this), + maX1(0), + maY1(0), + maX2(0), + maY2(0), + mpaTransform(0) + { + } + + SvgLineNode::~SvgLineNode() + { + if(mpaTransform) delete mpaTransform; + } + + const SvgStyleAttributes* SvgLineNode::getSvgStyleAttributes() const + { + static rtl::OUString aClassStr(rtl::OUString::createFromAscii("line")); + maSvgStyleAttributes.checkForCssStyle(aClassStr); + + return &maSvgStyleAttributes; + } + + void SvgLineNode::parseAttribute(const rtl::OUString& rTokenName, SVGToken aSVGToken, const rtl::OUString& aContent) + { + // call parent + SvgNode::parseAttribute(rTokenName, aSVGToken, aContent); + + // read style attributes + maSvgStyleAttributes.parseStyleAttribute(rTokenName, aSVGToken, aContent); + + // parse own + switch(aSVGToken) + { + case SVGTokenStyle: + { + maSvgStyleAttributes.readStyle(aContent); + break; + } + case SVGTokenX1: + { + SvgNumber aNum; + + if(readSingleNumber(aContent, aNum)) + { + setX1(aNum); + } + break; + } + case SVGTokenY1: + { + SvgNumber aNum; + + if(readSingleNumber(aContent, aNum)) + { + setY1(aNum); + } + break; + } + case SVGTokenX2: + { + SvgNumber aNum; + + if(readSingleNumber(aContent, aNum)) + { + setX2(aNum); + } + break; + } + case SVGTokenY2: + { + SvgNumber aNum; + + if(readSingleNumber(aContent, aNum)) + { + setY2(aNum); + } + break; + } + case SVGTokenTransform: + { + const basegfx::B2DHomMatrix aMatrix(readTransform(aContent, *this)); + + if(!aMatrix.isIdentity()) + { + setTransform(&aMatrix); + } + break; + } + default: + { + break; + } + } + } + + void SvgLineNode::decomposeSvgNode(drawinglayer::primitive2d::Primitive2DSequence& rTarget, bool /*bReferenced*/) const + { + const SvgStyleAttributes* pStyle = getSvgStyleAttributes(); + + if(pStyle) + { + const basegfx::B2DPoint X( + getX1().isSet() ? getX1().solve(*this, xcoordinate) : 0.0, + getY1().isSet() ? getY1().solve(*this, ycoordinate) : 0.0); + const basegfx::B2DPoint Y( + getX2().isSet() ? getX2().solve(*this, xcoordinate) : 0.0, + getY2().isSet() ? getY2().solve(*this, ycoordinate) : 0.0); + + if(!X.equal(Y)) + { + basegfx::B2DPolygon aPath; + + aPath.append(X); + aPath.append(Y); + + drawinglayer::primitive2d::Primitive2DSequence aNewTarget; + + pStyle->add_path(basegfx::B2DPolyPolygon(aPath), aNewTarget); + + if(aNewTarget.hasElements()) + { + pStyle->add_postProcess(rTarget, aNewTarget, getTransform()); + } + } + } + } + } // end of namespace svgreader +} // end of namespace svgio + +////////////////////////////////////////////////////////////////////////////// +// eof + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svgio/source/svgreader/svgmarkernode.cxx b/svgio/source/svgreader/svgmarkernode.cxx new file mode 100644 index 000000000000..444ff3266420 --- /dev/null +++ b/svgio/source/svgreader/svgmarkernode.cxx @@ -0,0 +1,213 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <svgio/svgreader/svgmarkernode.hxx> + +////////////////////////////////////////////////////////////////////////////// + +namespace svgio +{ + namespace svgreader + { + SvgMarkerNode::SvgMarkerNode( + SvgDocument& rDocument, + SvgNode* pParent) + : SvgNode(SVGTokenMarker, rDocument, pParent), + aPrimitives(), + maSvgStyleAttributes(*this), + mpViewBox(0), + maSvgAspectRatio(), + maRefX(0), + maRefY(0), + maMarkerUnits(strokeWidth), + maMarkerWidth(3), + maMarkerHeight(3), + mfAngle(0.0), + mbOrientAuto(false) + { + } + + SvgMarkerNode::~SvgMarkerNode() + { + if(mpViewBox) delete mpViewBox; + } + + const SvgStyleAttributes* SvgMarkerNode::getSvgStyleAttributes() const + { + static rtl::OUString aClassStr(rtl::OUString::createFromAscii("marker")); + maSvgStyleAttributes.checkForCssStyle(aClassStr); + + return &maSvgStyleAttributes; + } + + void SvgMarkerNode::parseAttribute(const rtl::OUString& rTokenName, SVGToken aSVGToken, const rtl::OUString& aContent) + { + // call parent + SvgNode::parseAttribute(rTokenName, aSVGToken, aContent); + + // read style attributes + maSvgStyleAttributes.parseStyleAttribute(rTokenName, aSVGToken, aContent); + + // parse own + switch(aSVGToken) + { + case SVGTokenStyle: + { + maSvgStyleAttributes.readStyle(aContent); + break; + } + case SVGTokenViewBox: + { + const basegfx::B2DRange aRange(readViewBox(aContent, *this)); + + if(!aRange.isEmpty()) + { + setViewBox(&aRange); + } + break; + } + case SVGTokenPreserveAspectRatio: + { + setSvgAspectRatio(readSvgAspectRatio(aContent)); + break; + } + case SVGTokenRefX: + { + SvgNumber aNum; + + if(readSingleNumber(aContent, aNum)) + { + setRefX(aNum); + } + break; + } + case SVGTokenRefY: + { + SvgNumber aNum; + + if(readSingleNumber(aContent, aNum)) + { + setRefY(aNum); + } + break; + } + case SVGTokenMarkerUnits: + { + if(aContent.getLength()) + { + static rtl::OUString aStrStrokeWidth(rtl::OUString::createFromAscii("strokeWidth")); + + if(aContent.match(aStrStrokeWidth, 0)) + { + setMarkerUnits(strokeWidth); + } + else if(aContent.match(commonStrings::aStrUserSpaceOnUse, 0)) + { + setMarkerUnits(userSpaceOnUse); + } + } + break; + } + case SVGTokenMarkerWidth: + { + SvgNumber aNum; + + if(readSingleNumber(aContent, aNum)) + { + if(aNum.isPositive()) + { + setMarkerWidth(aNum); + } + } + break; + } + case SVGTokenMarkerHeight: + { + SvgNumber aNum; + + if(readSingleNumber(aContent, aNum)) + { + if(aNum.isPositive()) + { + setMarkerHeight(aNum); + } + } + break; + } + case SVGTokenOrient: + { + const sal_Int32 nLen(aContent.getLength()); + + if(nLen) + { + static rtl::OUString aStrAuto(rtl::OUString::createFromAscii("auto")); + + if(aContent.match(aStrAuto, 0)) + { + setOrientAuto(true); + } + else + { + sal_Int32 nPos(0); + double fAngle(0.0); + + if(readAngle(aContent, nPos, fAngle, nLen)) + { + setAngle(fAngle); + } + } + } + break; + } + default: + { + break; + } + } + } + + const drawinglayer::primitive2d::Primitive2DSequence& SvgMarkerNode::getMarkerPrimitives() const + { + if(!aPrimitives.hasElements()) + { + decomposeSvgNode(const_cast< SvgMarkerNode* >(this)->aPrimitives, true); + } + + return aPrimitives; + } + + const basegfx::B2DRange* SvgMarkerNode::getCurrentViewPort() const + { + if(getViewBox()) + { + return getViewBox(); + } + else + { + return SvgNode::getCurrentViewPort(); + } + } + + } // end of namespace svgreader +} // end of namespace svgio + +////////////////////////////////////////////////////////////////////////////// +// eof + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svgio/source/svgreader/svgmasknode.cxx b/svgio/source/svgreader/svgmasknode.cxx new file mode 100644 index 000000000000..bc1ac3243e85 --- /dev/null +++ b/svgio/source/svgreader/svgmasknode.cxx @@ -0,0 +1,315 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <svgio/svgreader/svgmasknode.hxx> +#include <drawinglayer/primitive2d/transformprimitive2d.hxx> +#include <drawinglayer/primitive2d/transparenceprimitive2d.hxx> +#include <basegfx/matrix/b2dhommatrixtools.hxx> +#include <drawinglayer/geometry/viewinformation2d.hxx> +#include <drawinglayer/primitive2d/modifiedcolorprimitive2d.hxx> +#include <drawinglayer/primitive2d/maskprimitive2d.hxx> +#include <basegfx/polygon/b2dpolygontools.hxx> +#include <basegfx/polygon/b2dpolygon.hxx> + +////////////////////////////////////////////////////////////////////////////// + +namespace svgio +{ + namespace svgreader + { + SvgMaskNode::SvgMaskNode( + SvgDocument& rDocument, + SvgNode* pParent) + : SvgNode(SVGTokenMask, rDocument, pParent), + maSvgStyleAttributes(*this), + maX(SvgNumber(-10.0, Unit_percent, true)), + maY(SvgNumber(-10.0, Unit_percent, true)), + maWidth(SvgNumber(120.0, Unit_percent, true)), + maHeight(SvgNumber(120.0, Unit_percent, true)), + mpaTransform(0), + maMaskUnits(objectBoundingBox), + maMaskContentUnits(userSpaceOnUse) + { + } + + SvgMaskNode::~SvgMaskNode() + { + if(mpaTransform) delete mpaTransform; + } + + const SvgStyleAttributes* SvgMaskNode::getSvgStyleAttributes() const + { + return &maSvgStyleAttributes; + } + + void SvgMaskNode::parseAttribute(const rtl::OUString& rTokenName, SVGToken aSVGToken, const rtl::OUString& aContent) + { + // call parent + SvgNode::parseAttribute(rTokenName, aSVGToken, aContent); + + // read style attributes + maSvgStyleAttributes.parseStyleAttribute(rTokenName, aSVGToken, aContent); + + // parse own + switch(aSVGToken) + { + case SVGTokenStyle: + { + maSvgStyleAttributes.readStyle(aContent); + break; + } + case SVGTokenX: + { + SvgNumber aNum; + + if(readSingleNumber(aContent, aNum)) + { + setX(aNum); + } + break; + } + case SVGTokenY: + { + SvgNumber aNum; + + if(readSingleNumber(aContent, aNum)) + { + setY(aNum); + } + break; + } + case SVGTokenWidth: + { + SvgNumber aNum; + + if(readSingleNumber(aContent, aNum)) + { + if(aNum.isPositive()) + { + setWidth(aNum); + } + } + break; + } + case SVGTokenHeight: + { + SvgNumber aNum; + + if(readSingleNumber(aContent, aNum)) + { + if(aNum.isPositive()) + { + setHeight(aNum); + } + } + break; + } + case SVGTokenTransform: + { + const basegfx::B2DHomMatrix aMatrix(readTransform(aContent, *this)); + + if(!aMatrix.isIdentity()) + { + setTransform(&aMatrix); + } + break; + } + case SVGTokenMaskUnits: + { + if(aContent.getLength()) + { + if(aContent.match(commonStrings::aStrUserSpaceOnUse, 0)) + { + setMaskUnits(userSpaceOnUse); + } + else if(aContent.match(commonStrings::aStrObjectBoundingBox, 0)) + { + setMaskUnits(objectBoundingBox); + } + } + break; + } + case SVGTokenMaskContentUnits: + { + if(aContent.getLength()) + { + if(aContent.match(commonStrings::aStrUserSpaceOnUse, 0)) + { + setMaskContentUnits(userSpaceOnUse); + } + else if(aContent.match(commonStrings::aStrObjectBoundingBox, 0)) + { + setMaskContentUnits(objectBoundingBox); + } + } + break; + } + default: + { + break; + } + } + } + + void SvgMaskNode::decomposeSvgNode(drawinglayer::primitive2d::Primitive2DSequence& rTarget, bool bReferenced) const + { + drawinglayer::primitive2d::Primitive2DSequence aNewTarget; + + // decompose childs + SvgNode::decomposeSvgNode(aNewTarget, bReferenced); + + if(aNewTarget.hasElements()) + { + if(getTransform()) + { + // create embedding group element with transformation + const drawinglayer::primitive2d::Primitive2DReference xRef( + new drawinglayer::primitive2d::TransformPrimitive2D( + *getTransform(), + aNewTarget)); + + aNewTarget = drawinglayer::primitive2d::Primitive2DSequence(&xRef, 1); + } + + // append to current target + drawinglayer::primitive2d::appendPrimitive2DSequenceToPrimitive2DSequence(rTarget, aNewTarget); + } + } + + void SvgMaskNode::apply(drawinglayer::primitive2d::Primitive2DSequence& rTarget) const + { + if(rTarget.hasElements()) + { + drawinglayer::primitive2d::Primitive2DSequence aMaskTarget; + + // get mask definition as primitives + decomposeSvgNode(aMaskTarget, true); + + if(aMaskTarget.hasElements()) + { + // get range of content to be masked + const basegfx::B2DRange aContentRange( + drawinglayer::primitive2d::getB2DRangeFromPrimitive2DSequence( + rTarget, + drawinglayer::geometry::ViewInformation2D())); + const double fContentWidth(aContentRange.getWidth()); + const double fContentHeight(aContentRange.getHeight()); + + if(fContentWidth > 0.0 && fContentHeight > 0.0) + { + // create OffscreenBufferRange + basegfx::B2DRange aOffscreenBufferRange; + + if(objectBoundingBox == getMaskUnits()) + { + // fractions or percentages of the bounding box of the element to which the mask is applied + const double fX(Unit_percent == getX().getUnit() ? getX().getNumber() * 0.01 : getX().getNumber()); + const double fY(Unit_percent == getY().getUnit() ? getY().getNumber() * 0.01 : getY().getNumber()); + const double fW(Unit_percent == getWidth().getUnit() ? getWidth().getNumber() * 0.01 : getWidth().getNumber()); + const double fH(Unit_percent == getHeight().getUnit() ? getHeight().getNumber() * 0.01 : getHeight().getNumber()); + + aOffscreenBufferRange = basegfx::B2DRange( + aContentRange.getMinX() + (fX * fContentWidth), + aContentRange.getMinY() + (fY * fContentHeight), + aContentRange.getMinX() + ((fX + fW) * fContentWidth), + aContentRange.getMinY() + ((fY + fH) * fContentHeight)); + } + else + { + const double fX(getX().isSet() ? getX().solve(*this, xcoordinate) : 0.0); + const double fY(getY().isSet() ? getY().solve(*this, ycoordinate) : 0.0); + + aOffscreenBufferRange = basegfx::B2DRange( + fX, + fY, + fX + (getWidth().isSet() ? getWidth().solve(*this, xcoordinate) : 0.0), + fY + (getHeight().isSet() ? getHeight().solve(*this, ycoordinate) : 0.0)); + } + + if(objectBoundingBox == getMaskContentUnits()) + { + // mask is object-relative, embed in content transformation + const drawinglayer::primitive2d::Primitive2DReference xTransform( + new drawinglayer::primitive2d::TransformPrimitive2D( + basegfx::tools::createScaleTranslateB2DHomMatrix( + aContentRange.getRange(), + aContentRange.getMinimum()), + aMaskTarget)); + + aMaskTarget = drawinglayer::primitive2d::Primitive2DSequence(&xTransform, 1); + } + + // embed content to a ModifiedColorPrimitive2D since the definitions + // how content is used as alpha is special for Svg + { + const drawinglayer::primitive2d::Primitive2DReference xInverseMask( + new drawinglayer::primitive2d::ModifiedColorPrimitive2D( + aMaskTarget, + basegfx::BColorModifier( + basegfx::BColor(0.0, 0.0, 0.0), + 0.5, + basegfx::BCOLORMODIFYMODE_LUMINANCE_TO_ALPHA))); + + aMaskTarget = drawinglayer::primitive2d::Primitive2DSequence(&xInverseMask, 1); + } + + // prepare new content + drawinglayer::primitive2d::Primitive2DReference xNewContent( + new drawinglayer::primitive2d::TransparencePrimitive2D( + rTarget, + aMaskTarget)); + + // output up to now is defined by aContentRange and mask is oriented + // relative to it. It is possible that aOffscreenBufferRange defines + // a smaller area. In that case, embed to a mask primitive + if(!aOffscreenBufferRange.isInside(aContentRange)) + { + xNewContent = new drawinglayer::primitive2d::MaskPrimitive2D( + basegfx::B2DPolyPolygon( + basegfx::tools::createPolygonFromRect( + aOffscreenBufferRange)), + drawinglayer::primitive2d::Primitive2DSequence(&xNewContent, 1)); + } + + // redefine target. Use TransparencePrimitive2D with created mask + // geometry + rTarget = drawinglayer::primitive2d::Primitive2DSequence(&xNewContent, 1); + } + else + { + // content is geometrically empty + rTarget.realloc(0); + } + } + else + { + // An empty clipping path will completely clip away the element that had + // the clip-path property applied. (Svg spec) + rTarget.realloc(0); + } + } + } + + } // end of namespace svgreader +} // end of namespace svgio + +////////////////////////////////////////////////////////////////////////////// +// eof + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svgio/source/svgreader/svgnode.cxx b/svgio/source/svgreader/svgnode.cxx new file mode 100644 index 000000000000..74f29909e110 --- /dev/null +++ b/svgio/source/svgreader/svgnode.cxx @@ -0,0 +1,289 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <svgio/svgreader/svgnode.hxx> +#include <basegfx/polygon/b2dpolypolygontools.hxx> +#include <svgio/svgreader/svgdocument.hxx> +#include <svgio/svgreader/svgnode.hxx> +#include <svgio/svgreader/svgstyleattributes.hxx> + +////////////////////////////////////////////////////////////////////////////// + +namespace svgio +{ + namespace svgreader + { + const SvgStyleAttributes* SvgNode::getSvgStyleAttributes() const + { + return 0; + } + + SvgNode::SvgNode( + SVGToken aType, + SvgDocument& rDocument, + SvgNode* pParent) + : maType(aType), + mrDocument(rDocument), + mpParent(pParent), + mpAlternativeParent(0), + maChildren(), + mpId(0), + mpClass(0), + maXmlSpace(XmlSpace_notset) + { + OSL_ENSURE(SVGTokenUnknown != maType, "SvgNode with unknown type created (!)"); + + if(pParent) + { + pParent->maChildren.push_back(this); + } + else + { +#ifdef DBG_UTIL + if(SVGTokenSvg != getType()) + { + OSL_ENSURE(false, "No parent for this node (!)"); + } +#endif + } + } + + SvgNode::~SvgNode() + { + while(maChildren.size()) + { + delete maChildren[maChildren.size() - 1]; + maChildren.pop_back(); + } + + if(mpId) delete mpId; + if(mpClass) delete mpClass; + } + + void SvgNode::parseAttributes(const com::sun::star::uno::Reference< com::sun::star::xml::sax::XAttributeList >& xAttribs) + { + const sal_uInt32 nAttributes(xAttribs->getLength()); + + for(sal_uInt32 a(0); a < nAttributes; a++) + { + const ::rtl::OUString aTokenName(xAttribs->getNameByIndex(a)); + + parseAttribute(aTokenName, StrToSVGToken(aTokenName), xAttribs->getValueByIndex(a)); + } + } + + void SvgNode::parseAttribute(const rtl::OUString& /*rTokenName*/, SVGToken aSVGToken, const rtl::OUString& aContent) + { + switch(aSVGToken) + { + case SVGTokenId: + { + if(aContent.getLength()) + { + setId(&aContent); + } + break; + } + case SVGTokenClass: + { + if(aContent.getLength()) + { + setClass(&aContent); + } + break; + } + case SVGTokenXmlSpace: + { + if(aContent.getLength()) + { + static rtl::OUString aStrDefault(rtl::OUString::createFromAscii("default")); + static rtl::OUString aStrPreserve(rtl::OUString::createFromAscii("preserve")); + + if(aContent.match(aStrDefault)) + { + setXmlSpace(XmlSpace_default); + } + else if(aContent.match(aStrPreserve)) + { + setXmlSpace(XmlSpace_preserve); + } + } + break; + } + default: + { + break; + } + } + } + + void SvgNode::decomposeSvgNode(drawinglayer::primitive2d::Primitive2DSequence& rTarget, bool bReferenced) const + { + if(!bReferenced) + { + if(SVGTokenDefs == getType() || + SVGTokenSymbol == getType() || + SVGTokenClipPathNode == getType() || + SVGTokenMask == getType() || + SVGTokenMarker == getType() || + SVGTokenPattern == getType()) + { + // do not decompose defs or symbol nodes (these hold only style-like + // objects which may be used by referencing them) except when doing + // so controlled referenced + + // also do not decompose ClipPaths and Masks. These should be embedded + // in a defs node (which gets not decomposed by itself), but you never + // know + + // also not directly used are Markers and Patterns, only indirecty used + // by reference + return; + } + } + + const SvgNodeVector& rChildren = getChildren(); + + if(!rChildren.empty()) + { + const sal_uInt32 nCount(rChildren.size()); + + for(sal_uInt32 a(0); a < nCount; a++) + { + SvgNode* pCandidate = rChildren[a]; + + if(pCandidate) + { + drawinglayer::primitive2d::Primitive2DSequence aNewTarget; + + pCandidate->decomposeSvgNode(aNewTarget, bReferenced); + + if(aNewTarget.hasElements()) + { + drawinglayer::primitive2d::appendPrimitive2DSequenceToPrimitive2DSequence(rTarget, aNewTarget); + } + } + else + { + OSL_ENSURE(false, "Null-Pointer in child node list (!)"); + } + } + } + } + + const basegfx::B2DRange* SvgNode::getCurrentViewPort() const + { + if(getParent()) + { + return getParent()->getCurrentViewPort(); + } + else + { + return 0; + } + } + + double SvgNode::getCurrentFontSize() const + { + if(getSvgStyleAttributes()) + { + return getSvgStyleAttributes()->getFontSize().solve(*this, xcoordinate); + } + else if(getParent()) + { + return getParent()->getCurrentFontSize(); + } + else + { + return 0.0; + } + } + + double SvgNode::getCurrentXHeight() const + { + if(getSvgStyleAttributes()) + { + // for XHeight, use FontSize currently + return getSvgStyleAttributes()->getFontSize().solve(*this, ycoordinate); + } + else if(getParent()) + { + return getParent()->getCurrentXHeight(); + } + else + { + return 0.0; + } + } + + void SvgNode::setId(const rtl::OUString* pfId) + { + if(mpId) + { + mrDocument.removeSvgNodeFromMapper(*mpId); + delete mpId; + mpId = 0; + } + + if(pfId) + { + mpId = new rtl::OUString(*pfId); + mrDocument.addSvgNodeToMapper(*mpId, *this); + } + } + + void SvgNode::setClass(const rtl::OUString* pfClass) + { + if(mpClass) + { + mrDocument.removeSvgNodeFromMapper(*mpClass); + delete mpClass; + mpClass = 0; + } + + if(pfClass) + { + mpClass = new rtl::OUString(*pfClass); + mrDocument.addSvgNodeToMapper(*mpClass, *this); + } + } + + XmlSpace SvgNode::getXmlSpace() const + { + if(maXmlSpace != XmlSpace_notset) + { + return maXmlSpace; + } + + if(getParent()) + { + return getParent()->getXmlSpace(); + } + + // default is XmlSpace_default + return XmlSpace_default; + } + + } // end of namespace svgreader +} // end of namespace svgio + +////////////////////////////////////////////////////////////////////////////// +// eof + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svgio/source/svgreader/svgpaint.cxx b/svgio/source/svgreader/svgpaint.cxx new file mode 100644 index 000000000000..91c721236441 --- /dev/null +++ b/svgio/source/svgreader/svgpaint.cxx @@ -0,0 +1,34 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <svgio/svgreader/svgpaint.hxx> + +////////////////////////////////////////////////////////////////////////////// + +namespace svgio +{ + namespace svgreader + { + } // end of namespace svgreader +} // end of namespace svgio + +////////////////////////////////////////////////////////////////////////////// +// eof + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svgio/source/svgreader/svgpathnode.cxx b/svgio/source/svgreader/svgpathnode.cxx new file mode 100644 index 000000000000..cd66017a5765 --- /dev/null +++ b/svgio/source/svgreader/svgpathnode.cxx @@ -0,0 +1,133 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <svgio/svgreader/svgpathnode.hxx> +#include <basegfx/polygon/b2dpolypolygontools.hxx> + +////////////////////////////////////////////////////////////////////////////// + +namespace svgio +{ + namespace svgreader + { + SvgPathNode::SvgPathNode( + SvgDocument& rDocument, + SvgNode* pParent) + : SvgNode(SVGTokenPath, rDocument, pParent), + maSvgStyleAttributes(*this), + mpPolyPolygon(0), + mpaTransform(0), + maPathLength() + { + } + + SvgPathNode::~SvgPathNode() + { + if(mpPolyPolygon) delete mpPolyPolygon; + if(mpaTransform) delete mpaTransform; + } + + const SvgStyleAttributes* SvgPathNode::getSvgStyleAttributes() const + { + static rtl::OUString aClassStr(rtl::OUString::createFromAscii("path")); + maSvgStyleAttributes.checkForCssStyle(aClassStr); + + return &maSvgStyleAttributes; + } + + void SvgPathNode::parseAttribute(const rtl::OUString& rTokenName, SVGToken aSVGToken, const rtl::OUString& aContent) + { + // call parent + SvgNode::parseAttribute(rTokenName, aSVGToken, aContent); + + // read style attributes + maSvgStyleAttributes.parseStyleAttribute(rTokenName, aSVGToken, aContent); + + // parse own + switch(aSVGToken) + { + case SVGTokenStyle: + { + maSvgStyleAttributes.readStyle(aContent); + break; + } + case SVGTokenD: + { + basegfx::B2DPolyPolygon aPath; + + if(basegfx::tools::importFromSvgD(aPath, aContent)) + { + if(aPath.count()) + { + setPath(&aPath); + } + } + break; + } + case SVGTokenTransform: + { + const basegfx::B2DHomMatrix aMatrix(readTransform(aContent, *this)); + + if(!aMatrix.isIdentity()) + { + setTransform(&aMatrix); + } + break; + } + case SVGTokenPathLength: + { + SvgNumber aNum; + + if(readSingleNumber(aContent, aNum)) + { + setPathLength(aNum); + } + break; + } + default: + { + break; + } + } + } + + void SvgPathNode::decomposeSvgNode(drawinglayer::primitive2d::Primitive2DSequence& rTarget, bool /*bReferenced*/) const + { + // fill and/or stroke needed, also a path + const SvgStyleAttributes* pStyle = getSvgStyleAttributes(); + + if(pStyle && getPath()) + { + drawinglayer::primitive2d::Primitive2DSequence aNewTarget; + + pStyle->add_path(*getPath(), aNewTarget); + + if(aNewTarget.hasElements()) + { + pStyle->add_postProcess(rTarget, aNewTarget, getTransform()); + } + } + } + } // end of namespace svgreader +} // end of namespace svgio + +////////////////////////////////////////////////////////////////////////////// +// eof + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svgio/source/svgreader/svgpatternnode.cxx b/svgio/source/svgreader/svgpatternnode.cxx new file mode 100644 index 000000000000..6aa7a7cd63a3 --- /dev/null +++ b/svgio/source/svgreader/svgpatternnode.cxx @@ -0,0 +1,463 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <svgio/svgreader/svgpatternnode.hxx> +#include <svgio/svgreader/svgdocument.hxx> + +////////////////////////////////////////////////////////////////////////////// + +namespace svgio +{ + namespace svgreader + { + void SvgPatternNode::tryToFindLink() + { + if(!mpXLink && maXLink.getLength()) + { + mpXLink = dynamic_cast< const SvgPatternNode* >(getDocument().findSvgNodeById(maXLink)); + } + } + + SvgPatternNode::SvgPatternNode( + SvgDocument& rDocument, + SvgNode* pParent) + : SvgNode(SVGTokenPattern, rDocument, pParent), + aPrimitives(), + maSvgStyleAttributes(*this), + mpViewBox(0), + maSvgAspectRatio(), + maX(), + maY(), + maWidth(), + maHeight(), + mpPatternUnits(0), + mpPatternContentUnits(0), + mpaPatternTransform(0), + maXLink(), + mpXLink(0) + { + } + + SvgPatternNode::~SvgPatternNode() + { + if(mpViewBox) delete mpViewBox; + if(mpaPatternTransform) delete mpaPatternTransform; + if(mpPatternUnits) delete mpPatternUnits; + if(mpPatternContentUnits) delete mpPatternContentUnits; + } + + const SvgStyleAttributes* SvgPatternNode::getSvgStyleAttributes() const + { + static rtl::OUString aClassStr(rtl::OUString::createFromAscii("pattern")); + maSvgStyleAttributes.checkForCssStyle(aClassStr); + + return &maSvgStyleAttributes; + } + + void SvgPatternNode::parseAttribute(const rtl::OUString& rTokenName, SVGToken aSVGToken, const rtl::OUString& aContent) + { + // call parent + SvgNode::parseAttribute(rTokenName, aSVGToken, aContent); + + // read style attributes + maSvgStyleAttributes.parseStyleAttribute(rTokenName, aSVGToken, aContent); + + // parse own + switch(aSVGToken) + { + case SVGTokenStyle: + { + maSvgStyleAttributes.readStyle(aContent); + break; + } + case SVGTokenViewBox: + { + const basegfx::B2DRange aRange(readViewBox(aContent, *this)); + + if(!aRange.isEmpty()) + { + setViewBox(&aRange); + } + break; + } + case SVGTokenPreserveAspectRatio: + { + setSvgAspectRatio(readSvgAspectRatio(aContent)); + break; + } + case SVGTokenX: + { + SvgNumber aNum; + + if(readSingleNumber(aContent, aNum)) + { + setX(aNum); + } + break; + } + case SVGTokenY: + { + SvgNumber aNum; + + if(readSingleNumber(aContent, aNum)) + { + setY(aNum); + } + break; + } + case SVGTokenWidth: + { + SvgNumber aNum; + + if(readSingleNumber(aContent, aNum)) + { + if(aNum.isPositive()) + { + setWidth(aNum); + } + } + break; + } + case SVGTokenHeight: + { + SvgNumber aNum; + + if(readSingleNumber(aContent, aNum)) + { + if(aNum.isPositive()) + { + setHeight(aNum); + } + } + break; + } + case SVGTokenPatternUnits: + { + if(aContent.getLength()) + { + if(aContent.match(commonStrings::aStrUserSpaceOnUse, 0)) + { + setPatternUnits(userSpaceOnUse); + } + else if(aContent.match(commonStrings::aStrObjectBoundingBox, 0)) + { + setPatternUnits(objectBoundingBox); + } + } + break; + } + case SVGTokenPatternContentUnits: + { + if(aContent.getLength()) + { + if(aContent.match(commonStrings::aStrUserSpaceOnUse, 0)) + { + setPatternContentUnits(userSpaceOnUse); + } + else if(aContent.match(commonStrings::aStrObjectBoundingBox, 0)) + { + setPatternContentUnits(objectBoundingBox); + } + } + break; + } + case SVGTokenPatternTransform: + { + const basegfx::B2DHomMatrix aMatrix(readTransform(aContent, *this)); + + if(!aMatrix.isIdentity()) + { + setPatternTransform(&aMatrix); + } + break; + } + case SVGTokenXlinkHref: + { + const sal_Int32 nLen(aContent.getLength()); + + if(nLen && sal_Unicode('#') == aContent[0]) + { + maXLink = aContent.copy(1); + tryToFindLink(); + } + break; + } + default: + { + break; + } + } + } + + void SvgPatternNode::getValuesRelative(double& rfX, double& rfY, double& rfW, double& rfH, const basegfx::B2DRange& rGeoRange, SvgNode& rUser) const + { + double fTargetWidth(rGeoRange.getWidth()); + double fTargetHeight(rGeoRange.getHeight()); + + if(fTargetWidth > 0.0 && fTargetHeight > 0.0) + { + const SvgUnits aPatternUnits(getPatternUnits() ? *getPatternUnits() : objectBoundingBox); + + if(objectBoundingBox == aPatternUnits) + { + rfW = (getWidth().isSet()) ? getWidth().getNumber() : 0.0; + rfH = (getHeight().isSet()) ? getHeight().getNumber() : 0.0; + + if(Unit_percent == getWidth().getUnit()) + { + rfW *= 0.01; + } + + if(Unit_percent == getHeight().getUnit()) + { + rfH *= 0.01; + } + } + else + { + rfW = (getWidth().isSet()) ? getWidth().solve(rUser, xcoordinate) : 0.0; + rfH = (getHeight().isSet()) ? getHeight().solve(rUser, ycoordinate) : 0.0; + + // make relative to rGeoRange + rfW /= fTargetWidth; + rfH /= fTargetHeight; + } + + if(rfW > 0.0 && rfH > 0.0) + { + if(objectBoundingBox == aPatternUnits) + { + rfX = (getX().isSet()) ? getX().getNumber() : 0.0; + rfY = (getY().isSet()) ? getY().getNumber() : 0.0; + + if(Unit_percent == getX().getUnit()) + { + rfX *= 0.01; + } + + if(Unit_percent == getY().getUnit()) + { + rfY *= 0.01; + } + } + else + { + rfX = (getX().isSet()) ? getX().solve(rUser, xcoordinate) : 0.0; + rfY = (getY().isSet()) ? getY().solve(rUser, ycoordinate) : 0.0; + + // make relative to rGeoRange + rfX = (rfX - rGeoRange.getMinX()) / fTargetWidth; + rfY = (rfY - rGeoRange.getMinY()) / fTargetHeight; + } + } + } + } + + const drawinglayer::primitive2d::Primitive2DSequence& SvgPatternNode::getPatternPrimitives() const + { + if(!aPrimitives.hasElements()) + { + decomposeSvgNode(const_cast< SvgPatternNode* >(this)->aPrimitives, true); + } + + if(!aPrimitives.hasElements() && maXLink.getLength()) + { + const_cast< SvgPatternNode* >(this)->tryToFindLink(); + + if(mpXLink) + { + return mpXLink->getPatternPrimitives(); + } + } + + return aPrimitives; + } + + const basegfx::B2DRange* SvgPatternNode::getCurrentViewPort() const + { + if(getViewBox()) + { + return getViewBox(); + } + else + { + return SvgNode::getCurrentViewPort(); + } + } + + const basegfx::B2DRange* SvgPatternNode::getViewBox() const + { + if(mpViewBox) + { + return mpViewBox; + } + + const_cast< SvgPatternNode* >(this)->tryToFindLink(); + + if(mpXLink) + { + return mpXLink->getViewBox(); + } + + return 0; + } + + const SvgAspectRatio& SvgPatternNode::getSvgAspectRatio() const + { + if(maSvgAspectRatio.isSet()) + { + return maSvgAspectRatio; + } + + const_cast< SvgPatternNode* >(this)->tryToFindLink(); + + if(mpXLink) + { + return mpXLink->getSvgAspectRatio(); + } + + return maSvgAspectRatio; + } + + const SvgNumber& SvgPatternNode::getX() const + { + if(maX.isSet()) + { + return maX; + } + + const_cast< SvgPatternNode* >(this)->tryToFindLink(); + + if(mpXLink) + { + return mpXLink->getX(); + } + + return maX; + } + + const SvgNumber& SvgPatternNode::getY() const + { + if(maY.isSet()) + { + return maY; + } + + const_cast< SvgPatternNode* >(this)->tryToFindLink(); + + if(mpXLink) + { + return mpXLink->getY(); + } + + return maY; + } + + const SvgNumber& SvgPatternNode::getWidth() const + { + if(maWidth.isSet()) + { + return maWidth; + } + + const_cast< SvgPatternNode* >(this)->tryToFindLink(); + + if(mpXLink) + { + return mpXLink->getWidth(); + } + + return maWidth; + } + + const SvgNumber& SvgPatternNode::getHeight() const + { + if(maHeight.isSet()) + { + return maHeight; + } + + const_cast< SvgPatternNode* >(this)->tryToFindLink(); + + if(mpXLink) + { + return mpXLink->getHeight(); + } + + return maHeight; + } + + const SvgUnits* SvgPatternNode::getPatternUnits() const + { + if(mpPatternUnits) + { + return mpPatternUnits; + } + + const_cast< SvgPatternNode* >(this)->tryToFindLink(); + + if(mpXLink) + { + return mpXLink->getPatternUnits(); + } + + return 0; + } + + const SvgUnits* SvgPatternNode::getPatternContentUnits() const + { + if(mpPatternContentUnits) + { + return mpPatternContentUnits; + } + + const_cast< SvgPatternNode* >(this)->tryToFindLink(); + + if(mpXLink) + { + return mpXLink->getPatternContentUnits(); + } + + return 0; + } + + const basegfx::B2DHomMatrix* SvgPatternNode::getPatternTransform() const + { + if(mpaPatternTransform) + { + return mpaPatternTransform; + } + + const_cast< SvgPatternNode* >(this)->tryToFindLink(); + + if(mpXLink) + { + return mpXLink->getPatternTransform(); + } + + return 0; + } + + } // end of namespace svgreader +} // end of namespace svgio + +////////////////////////////////////////////////////////////////////////////// +// eof + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svgio/source/svgreader/svgpolynode.cxx b/svgio/source/svgreader/svgpolynode.cxx new file mode 100644 index 000000000000..a814402d46f8 --- /dev/null +++ b/svgio/source/svgreader/svgpolynode.cxx @@ -0,0 +1,130 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <svgio/svgreader/svgpolynode.hxx> +#include <basegfx/polygon/b2dpolygon.hxx> +#include <basegfx/polygon/b2dpolypolygontools.hxx> + +////////////////////////////////////////////////////////////////////////////// + +namespace svgio +{ + namespace svgreader + { + SvgPolyNode::SvgPolyNode( + SvgDocument& rDocument, + SvgNode* pParent, + bool bIsPolyline) + : SvgNode(SVGTokenPolygon, rDocument, pParent), + maSvgStyleAttributes(*this), + mpPolygon(0), + mpaTransform(0), + mbIsPolyline(bIsPolyline) + { + } + + SvgPolyNode::~SvgPolyNode() + { + if(mpaTransform) delete mpaTransform; + if(mpPolygon) delete mpPolygon; + } + + const SvgStyleAttributes* SvgPolyNode::getSvgStyleAttributes() const + { + static rtl::OUString aClassStrA(rtl::OUString::createFromAscii("polygon")); + static rtl::OUString aClassStrB(rtl::OUString::createFromAscii("polyline")); + maSvgStyleAttributes.checkForCssStyle(mbIsPolyline? aClassStrB : aClassStrA); + + return &maSvgStyleAttributes; + } + + void SvgPolyNode::parseAttribute(const rtl::OUString& rTokenName, SVGToken aSVGToken, const rtl::OUString& aContent) + { + // call parent + SvgNode::parseAttribute(rTokenName, aSVGToken, aContent); + + // read style attributes + maSvgStyleAttributes.parseStyleAttribute(rTokenName, aSVGToken, aContent); + + // parse own + switch(aSVGToken) + { + case SVGTokenStyle: + { + maSvgStyleAttributes.readStyle(aContent); + break; + } + case SVGTokenPoints: + { + basegfx::B2DPolygon aPath; + + if(basegfx::tools::importFromSvgPoints(aPath, aContent)) + { + if(aPath.count()) + { + if(!isPolyline()) + { + aPath.setClosed(true); + } + + setPolygon(&aPath); + } + } + break; + } + case SVGTokenTransform: + { + const basegfx::B2DHomMatrix aMatrix(readTransform(aContent, *this)); + + if(!aMatrix.isIdentity()) + { + setTransform(&aMatrix); + } + break; + } + default: + { + break; + } + } + } + + void SvgPolyNode::decomposeSvgNode(drawinglayer::primitive2d::Primitive2DSequence& rTarget, bool /*bReferenced*/) const + { + const SvgStyleAttributes* pStyle = getSvgStyleAttributes(); + + if(pStyle && getPolygon()) + { + drawinglayer::primitive2d::Primitive2DSequence aNewTarget; + + pStyle->add_path(basegfx::B2DPolyPolygon(*getPolygon()), aNewTarget); + + if(aNewTarget.hasElements()) + { + pStyle->add_postProcess(rTarget, aNewTarget, getTransform()); + } + } + } + } // end of namespace svgreader +} // end of namespace svgio + +////////////////////////////////////////////////////////////////////////////// +// eof + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svgio/source/svgreader/svgrectnode.cxx b/svgio/source/svgreader/svgrectnode.cxx new file mode 100644 index 000000000000..e826b8546f03 --- /dev/null +++ b/svgio/source/svgreader/svgrectnode.cxx @@ -0,0 +1,227 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <svgio/svgreader/svgrectnode.hxx> +#include <basegfx/polygon/b2dpolygon.hxx> +#include <basegfx/polygon/b2dpolygontools.hxx> + +////////////////////////////////////////////////////////////////////////////// + +namespace svgio +{ + namespace svgreader + { + SvgRectNode::SvgRectNode( + SvgDocument& rDocument, + SvgNode* pParent) + : SvgNode(SVGTokenRect, rDocument, pParent), + maSvgStyleAttributes(*this), + maX(0), + maY(0), + maWidth(0), + maHeight(0), + maRx(0), + maRy(0), + mpaTransform(0) + { + } + + SvgRectNode::~SvgRectNode() + { + if(mpaTransform) delete mpaTransform; + } + + const SvgStyleAttributes* SvgRectNode::getSvgStyleAttributes() const + { + static rtl::OUString aClassStr(rtl::OUString::createFromAscii("rect")); + maSvgStyleAttributes.checkForCssStyle(aClassStr); + + return &maSvgStyleAttributes; + } + + void SvgRectNode::parseAttribute(const rtl::OUString& rTokenName, SVGToken aSVGToken, const rtl::OUString& aContent) + { + // call parent + SvgNode::parseAttribute(rTokenName, aSVGToken, aContent); + + // read style attributes + maSvgStyleAttributes.parseStyleAttribute(rTokenName, aSVGToken, aContent); + + // parse own + switch(aSVGToken) + { + case SVGTokenStyle: + { + maSvgStyleAttributes.readStyle(aContent); + break; + } + case SVGTokenX: + { + SvgNumber aNum; + + if(readSingleNumber(aContent, aNum)) + { + setX(aNum); + } + break; + } + case SVGTokenY: + { + SvgNumber aNum; + + if(readSingleNumber(aContent, aNum)) + { + setY(aNum); + } + break; + } + case SVGTokenWidth: + { + SvgNumber aNum; + + if(readSingleNumber(aContent, aNum)) + { + if(aNum.isPositive()) + { + setWidth(aNum); + } + } + break; + } + case SVGTokenHeight: + { + SvgNumber aNum; + + if(readSingleNumber(aContent, aNum)) + { + if(aNum.isPositive()) + { + setHeight(aNum); + } + } + break; + } + case SVGTokenRx: + { + SvgNumber aNum; + + if(readSingleNumber(aContent, aNum)) + { + if(aNum.isPositive()) + { + setRx(aNum); + } + } + break; + } + case SVGTokenRy: + { + SvgNumber aNum; + + if(readSingleNumber(aContent, aNum)) + { + if(aNum.isPositive()) + { + setRy(aNum); + } + } + break; + } + case SVGTokenTransform: + { + const basegfx::B2DHomMatrix aMatrix(readTransform(aContent, *this)); + + if(!aMatrix.isIdentity()) + { + setTransform(&aMatrix); + } + break; + } + default: + { + break; + } + } + } + + void SvgRectNode::decomposeSvgNode(drawinglayer::primitive2d::Primitive2DSequence& rTarget, bool /*bReferenced*/) const + { + // get size range and create path + const SvgStyleAttributes* pStyle = getSvgStyleAttributes(); + + if(pStyle && getWidth().isSet() && getHeight().isSet()) + { + const double fWidth(getWidth().solve(*this, xcoordinate)); + const double fHeight(getHeight().solve(*this, ycoordinate)); + + if(fWidth > 0.0 && fHeight > 0.0) + { + const double fX(getX().isSet() ? getX().solve(*this, xcoordinate) : 0.0); + const double fY(getY().isSet() ? getY().solve(*this, ycoordinate) : 0.0); + const basegfx::B2DRange aRange(fX, fY, fX + fWidth, fY + fHeight); + basegfx::B2DPolygon aPath; + + if(getRx().isSet() || getRy().isSet()) + { + double frX(getRx().isSet() ? getRx().solve(*this, xcoordinate) : 0.0); + double frY(getRy().isSet() ? getRy().solve(*this, ycoordinate) : 0.0); + + frX = std::max(0.0, frX); + frY = std::max(0.0, frY); + + if(0.0 == frY && frX > 0.0) + { + frY = frX; + } + else if(0.0 == frX && frY > 0.0) + { + frX = frY; + } + + frX /= fWidth; + frY /= fHeight; + + frX = std::min(0.5, frX); + frY = std::min(0.5, frY); + + aPath = basegfx::tools::createPolygonFromRect(aRange, frX * 2.0, frY * 2.0); + } + else + { + aPath = basegfx::tools::createPolygonFromRect(aRange); + } + + drawinglayer::primitive2d::Primitive2DSequence aNewTarget; + + pStyle->add_path(basegfx::B2DPolyPolygon(aPath), aNewTarget); + + if(aNewTarget.hasElements()) + { + pStyle->add_postProcess(rTarget, aNewTarget, getTransform()); + } + } + } + } + } // end of namespace svgreader +} // end of namespace svgio + +////////////////////////////////////////////////////////////////////////////// +// eof + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svgio/source/svgreader/svgstyleattributes.cxx b/svgio/source/svgreader/svgstyleattributes.cxx new file mode 100644 index 000000000000..1a2755e52b1c --- /dev/null +++ b/svgio/source/svgreader/svgstyleattributes.cxx @@ -0,0 +1,2489 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <svgio/svgreader/svgstyleattributes.hxx> +#include <drawinglayer/primitive2d/transformprimitive2d.hxx> +#include <drawinglayer/primitive2d/polypolygonprimitive2d.hxx> +#include <svgio/svgreader/svgnode.hxx> +#include <svgio/svgreader/svgdocument.hxx> +#include <drawinglayer/primitive2d/svggradientprimitive2d.hxx> +#include <svgio/svgreader/svggradientnode.hxx> +#include <drawinglayer/primitive2d/unifiedtransparenceprimitive2d.hxx> +#include <basegfx/vector/b2enums.hxx> +#include <drawinglayer/processor2d/linegeometryextractor2d.hxx> +#include <drawinglayer/processor2d/textaspolygonextractor2d.hxx> +#include <basegfx/polygon/b2dpolypolygoncutter.hxx> +#include <svgio/svgreader/svgclippathnode.hxx> +#include <svgio/svgreader/svgmasknode.hxx> +#include <basegfx/polygon/b2dpolypolygoncutter.hxx> +#include <basegfx/polygon/b2dpolypolygontools.hxx> +#include <svgio/svgreader/svgmarkernode.hxx> +#include <basegfx/curve/b2dcubicbezier.hxx> +#include <svgio/svgreader/svgpatternnode.hxx> +#include <drawinglayer/primitive2d/patternfillprimitive2d.hxx> +#include <basegfx/polygon/b2dpolygontools.hxx> +#include <drawinglayer/primitive2d/maskprimitive2d.hxx> + +////////////////////////////////////////////////////////////////////////////// + +namespace svgio +{ + namespace svgreader + { + basegfx::B2DLineJoin StrokeLinejoinToB2DLineJoin(StrokeLinejoin aStrokeLinejoin) + { + if(StrokeLinejoin_round == aStrokeLinejoin) + { + return basegfx::B2DLINEJOIN_ROUND; + } + else if(StrokeLinejoin_bevel == aStrokeLinejoin) + { + return basegfx::B2DLINEJOIN_BEVEL; + } + + return basegfx::B2DLINEJOIN_MITER; + } + + com::sun::star::drawing::LineCap StrokeLinecapToDrawingLineCap(StrokeLinecap aStrokeLinecap) + { + switch(aStrokeLinecap) + { + default: /* StrokeLinecap_notset, StrokeLinecap_butt */ + { + return com::sun::star::drawing::LineCap_BUTT; + break; + } + case StrokeLinecap_round: + { + return com::sun::star::drawing::LineCap_ROUND; + break; + } + case StrokeLinecap_square: + { + return com::sun::star::drawing::LineCap_SQUARE; + break; + } + } + } + + FontStretch getWider(FontStretch aSource) + { + switch(aSource) + { + case FontStretch_ultra_condensed: aSource = FontStretch_extra_condensed; break; + case FontStretch_extra_condensed: aSource = FontStretch_condensed; break; + case FontStretch_condensed: aSource = FontStretch_semi_condensed; break; + case FontStretch_semi_condensed: aSource = FontStretch_normal; break; + case FontStretch_normal: aSource = FontStretch_semi_expanded; break; + case FontStretch_semi_expanded: aSource = FontStretch_expanded; break; + case FontStretch_expanded: aSource = FontStretch_extra_expanded; break; + case FontStretch_extra_expanded: aSource = FontStretch_ultra_expanded; break; + default: break; + } + + return aSource; + } + + FontStretch getNarrower(FontStretch aSource) + { + switch(aSource) + { + case FontStretch_extra_condensed: aSource = FontStretch_ultra_condensed; break; + case FontStretch_condensed: aSource = FontStretch_extra_condensed; break; + case FontStretch_semi_condensed: aSource = FontStretch_condensed; break; + case FontStretch_normal: aSource = FontStretch_semi_condensed; break; + case FontStretch_semi_expanded: aSource = FontStretch_normal; break; + case FontStretch_expanded: aSource = FontStretch_semi_expanded; break; + case FontStretch_extra_expanded: aSource = FontStretch_expanded; break; + case FontStretch_ultra_expanded: aSource = FontStretch_extra_expanded; break; + default: break; + } + + return aSource; + } + + FontWeight getBolder(FontWeight aSource) + { + switch(aSource) + { + case FontWeight_100: aSource = FontWeight_200; break; + case FontWeight_200: aSource = FontWeight_300; break; + case FontWeight_300: aSource = FontWeight_400; break; + case FontWeight_400: aSource = FontWeight_500; break; + case FontWeight_500: aSource = FontWeight_600; break; + case FontWeight_600: aSource = FontWeight_700; break; + case FontWeight_700: aSource = FontWeight_800; break; + case FontWeight_800: aSource = FontWeight_900; break; + default: break; + } + + return aSource; + } + + FontWeight getLighter(FontWeight aSource) + { + switch(aSource) + { + case FontWeight_200: aSource = FontWeight_100; break; + case FontWeight_300: aSource = FontWeight_200; break; + case FontWeight_400: aSource = FontWeight_300; break; + case FontWeight_500: aSource = FontWeight_400; break; + case FontWeight_600: aSource = FontWeight_500; break; + case FontWeight_700: aSource = FontWeight_600; break; + case FontWeight_800: aSource = FontWeight_700; break; + case FontWeight_900: aSource = FontWeight_800; break; + default: break; + } + + return aSource; + } + + ::FontWeight getVclFontWeight(FontWeight aSource) + { + ::FontWeight nRetval(WEIGHT_NORMAL); + + switch(aSource) + { + case FontWeight_100: nRetval = WEIGHT_ULTRALIGHT; break; + case FontWeight_200: nRetval = WEIGHT_LIGHT; break; + case FontWeight_300: nRetval = WEIGHT_SEMILIGHT; break; + case FontWeight_400: nRetval = WEIGHT_NORMAL; break; + case FontWeight_500: nRetval = WEIGHT_MEDIUM; break; + case FontWeight_600: nRetval = WEIGHT_SEMIBOLD; break; + case FontWeight_700: nRetval = WEIGHT_BOLD; break; + case FontWeight_800: nRetval = WEIGHT_ULTRABOLD; break; + case FontWeight_900: nRetval = WEIGHT_BLACK; break; + default: break; + } + + return nRetval; + } + + void SvgStyleAttributes::readStyle(const rtl::OUString& rCandidate) + { + const sal_Int32 nLen(rCandidate.getLength()); + sal_Int32 nPos(0); + + while(nPos < nLen) + { + const sal_Int32 nInitPos(nPos); + skip_char(rCandidate, sal_Unicode(' '), nPos, nLen); + rtl::OUStringBuffer aTokenName; + copyString(rCandidate, nPos, aTokenName, nLen); + + if(aTokenName.getLength()) + { + skip_char(rCandidate, sal_Unicode(' '), sal_Unicode(':'), nPos, nLen); + rtl::OUStringBuffer aTokenValue; + copyToLimiter(rCandidate, sal_Unicode(';'), nPos, aTokenValue, nLen); + skip_char(rCandidate, sal_Unicode(' '), sal_Unicode(';'), nPos, nLen); + const rtl::OUString aOUTokenName(aTokenName.makeStringAndClear()); + const rtl::OUString aOUTokenValue(aTokenValue.makeStringAndClear()); + + parseStyleAttribute(aOUTokenName, StrToSVGToken(aOUTokenName), aOUTokenValue); + } + + if(nInitPos == nPos) + { + OSL_ENSURE(false, "Could not interpret on current position (!)"); + nPos++; + } + } + } + + void SvgStyleAttributes::checkForCssStyle(const rtl::OUString& rClassStr) const + { + if(!mpCssStyleParent) + { + const SvgDocument& rDocument = mrOwner.getDocument(); + const SvgStyleAttributes* pNew = 0; + + if(rDocument.hasSvgStyleAttributesById()) + { + if(mrOwner.getClass()) + { + rtl::OUString aId(rtl::OUString::createFromAscii(".")); + aId = aId + *mrOwner.getClass(); + pNew = rDocument.findSvgStyleAttributesById(aId); + + if(!pNew && rClassStr.getLength()) + { + aId = rClassStr + aId; + + pNew = rDocument.findSvgStyleAttributesById(aId); + } + } + + if(!pNew && mrOwner.getId()) + { + pNew = rDocument.findSvgStyleAttributesById(*mrOwner.getId()); + } + + if(!pNew && rClassStr.getLength()) + { + pNew = rDocument.findSvgStyleAttributesById(rClassStr); + } + + if(pNew) + { + // found css style, set as parent + const_cast< SvgStyleAttributes* >(this)->mpCssStyleParent = pNew; + } + } + } + } + + const SvgStyleAttributes* SvgStyleAttributes::getParentStyle() const + { + if(mpCssStyleParent) + { + return mpCssStyleParent; + } + + if(mrOwner.getParent()) + { + return mrOwner.getParent()->getSvgStyleAttributes(); + } + + return 0; + } + + void SvgStyleAttributes::add_text( + drawinglayer::primitive2d::Primitive2DSequence& rTarget, + drawinglayer::primitive2d::Primitive2DSequence& rSource) const + { + if(rSource.hasElements()) + { + // at this point the primitives in rSource are of type TextSimplePortionPrimitive2D + // or TextDecoratedPortionPrimitive2D and have the Fill Color (pAttributes->getFill()) + // set. When another fill is used and also evtl. stroke is set it gets necessary to + // dismantle to geometry and add needed primitives + const basegfx::BColor* pFill = getFill(); + const SvgGradientNode* pFillGradient = getSvgGradientNodeFill(); + const SvgPatternNode* pFillPattern = getSvgPatternNodeFill(); + const basegfx::BColor* pStroke = getStroke(); + const SvgGradientNode* pStrokeGradient = getSvgGradientNodeStroke(); + const SvgPatternNode* pStrokePattern = getSvgPatternNodeStroke(); + basegfx::B2DPolyPolygon aMergedArea; + + if(pFillGradient || pFillPattern || pStroke || pStrokeGradient || pStrokePattern) + { + // text geometry is needed, create + // use neutral ViewInformation and create LineGeometryExtractor2D + const drawinglayer::geometry::ViewInformation2D aViewInformation2D; + drawinglayer::processor2d::TextAsPolygonExtractor2D aExtractor(aViewInformation2D); + + // proccess + aExtractor.process(rSource); + + // get results + const drawinglayer::processor2d::TextAsPolygonDataNodeVector& rResult = aExtractor.getTarget(); + const sal_uInt32 nResultCount(rResult.size()); + basegfx::B2DPolyPolygonVector aTextFillVector; + aTextFillVector.reserve(nResultCount); + + for(sal_uInt32 a(0); a < nResultCount; a++) + { + const drawinglayer::processor2d::TextAsPolygonDataNode& rCandidate = rResult[a]; + + if(rCandidate.getIsFilled()) + { + aTextFillVector.push_back(rCandidate.getB2DPolyPolygon()); + } + } + + if(!aTextFillVector.empty()) + { + aMergedArea = basegfx::tools::mergeToSinglePolyPolygon(aTextFillVector); + } + } + + const bool bStrokeUsed(pStroke || pStrokeGradient || pStrokePattern); + + // add fill. Use geometry even for simple color fill when stroke + // is used, else text rendering and the geometry-based stroke will + // normally not really match optically due to divrese system text + // renderers + if(aMergedArea.count() && (pFillGradient || pFillPattern || bStrokeUsed)) + { + // create text fill content based on geometry + add_fill(aMergedArea, rTarget, aMergedArea.getB2DRange()); + } + else if(pFill) + { + // add the already prepared primitives for single color fill + drawinglayer::primitive2d::appendPrimitive2DSequenceToPrimitive2DSequence(rTarget, rSource); + } + + // add stroke + if(aMergedArea.count() && bStrokeUsed) + { + // create text stroke content + add_stroke(aMergedArea, rTarget, aMergedArea.getB2DRange()); + } + } + } + + void SvgStyleAttributes::add_fillGradient( + const basegfx::B2DPolyPolygon& rPath, + drawinglayer::primitive2d::Primitive2DSequence& rTarget, + const SvgGradientNode& rFillGradient, + const basegfx::B2DRange& rGeoRange) const + { + // create fill content + drawinglayer::primitive2d::SvgGradientEntryVector aSvgGradientEntryVector; + + // get the color stops + rFillGradient.collectGradientEntries(aSvgGradientEntryVector); + + if(!aSvgGradientEntryVector.empty()) + { + basegfx::B2DHomMatrix aGeoToUnit; + + if(rFillGradient.getGradientTransform()) + { + aGeoToUnit = *rFillGradient.getGradientTransform(); + } + + if(userSpaceOnUse == rFillGradient.getGradientUnits()) + { + aGeoToUnit.translate(-rGeoRange.getMinX(), -rGeoRange.getMinY()); + aGeoToUnit.scale(1.0 / rGeoRange.getWidth(), 1.0 / rGeoRange.getHeight()); + } + + if(SVGTokenLinearGradient == rFillGradient.getType()) + { + basegfx::B2DPoint aStart(0.0, 0.0); + basegfx::B2DPoint aEnd(1.0, 0.0); + + if(userSpaceOnUse == rFillGradient.getGradientUnits()) + { + // all possible units + aStart.setX(rFillGradient.getX1().solve(mrOwner, xcoordinate)); + aStart.setY(rFillGradient.getY1().solve(mrOwner, ycoordinate)); + aEnd.setX(rFillGradient.getX2().solve(mrOwner, xcoordinate)); + aEnd.setY(rFillGradient.getY2().solve(mrOwner, ycoordinate)); + } + else + { + // fractions or percent relative to object bounds + const SvgNumber X1(rFillGradient.getX1()); + const SvgNumber Y1(rFillGradient.getY1()); + const SvgNumber X2(rFillGradient.getX2()); + const SvgNumber Y2(rFillGradient.getY2()); + + aStart.setX(Unit_percent == X1.getUnit() ? X1.getNumber() * 0.01 : X1.getNumber()); + aStart.setY(Unit_percent == Y1.getUnit() ? Y1.getNumber() * 0.01 : Y1.getNumber()); + aEnd.setX(Unit_percent == X2.getUnit() ? X2.getNumber() * 0.01 : X2.getNumber()); + aEnd.setY(Unit_percent == Y2.getUnit() ? Y2.getNumber() * 0.01 : Y2.getNumber()); + } + + if(!aGeoToUnit.isIdentity()) + { + aStart *= aGeoToUnit; + aEnd *= aGeoToUnit; + } + + drawinglayer::primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence( + rTarget, + new drawinglayer::primitive2d::SvgLinearGradientPrimitive2D( + rPath, + aSvgGradientEntryVector, + aStart, + aEnd, + rFillGradient.getSpreadMethod())); + } + else + { + basegfx::B2DPoint aStart(0.5, 0.5); + basegfx::B2DPoint aFocal; + double fRadius(0.5); + const SvgNumber* pFx = rFillGradient.getFx(); + const SvgNumber* pFy = rFillGradient.getFy(); + const bool bFocal(pFx || pFy); + + if(userSpaceOnUse == rFillGradient.getGradientUnits()) + { + // all possible units + aStart.setX(rFillGradient.getCx().solve(mrOwner, xcoordinate)); + aStart.setY(rFillGradient.getCy().solve(mrOwner, ycoordinate)); + fRadius = rFillGradient.getR().solve(mrOwner, length); + + if(bFocal) + { + aFocal.setX(pFx ? pFx->solve(mrOwner, xcoordinate) : aStart.getX()); + aFocal.setY(pFy ? pFy->solve(mrOwner, ycoordinate) : aStart.getY()); + } + } + else + { + // fractions or percent relative to object bounds + const SvgNumber Cx(rFillGradient.getCx()); + const SvgNumber Cy(rFillGradient.getCy()); + const SvgNumber R(rFillGradient.getR()); + + aStart.setX(Unit_percent == Cx.getUnit() ? Cx.getNumber() * 0.01 : Cx.getNumber()); + aStart.setY(Unit_percent == Cy.getUnit() ? Cy.getNumber() * 0.01 : Cy.getNumber()); + fRadius = (Unit_percent == R.getUnit()) ? R.getNumber() * 0.01 : R.getNumber(); + + if(bFocal) + { + aFocal.setX(pFx ? (Unit_percent == pFx->getUnit() ? pFx->getNumber() * 0.01 : pFx->getNumber()) : aStart.getX()); + aFocal.setY(pFy ? (Unit_percent == pFy->getUnit() ? pFy->getNumber() * 0.01 : pFy->getNumber()) : aStart.getY()); + } + } + + if(!aGeoToUnit.isIdentity()) + { + aStart *= aGeoToUnit; + fRadius = (aGeoToUnit * basegfx::B2DVector(fRadius, 0.0)).getLength(); + + if(bFocal) + { + aFocal *= aGeoToUnit; + } + } + + drawinglayer::primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence( + rTarget, + new drawinglayer::primitive2d::SvgRadialGradientPrimitive2D( + rPath, + aSvgGradientEntryVector, + aStart, + fRadius, + rFillGradient.getSpreadMethod(), + bFocal ? &aFocal : 0)); + } + } + } + + void SvgStyleAttributes::add_fillPatternTransform( + const basegfx::B2DPolyPolygon& rPath, + drawinglayer::primitive2d::Primitive2DSequence& rTarget, + const SvgPatternNode& rFillPattern, + const basegfx::B2DRange& rGeoRange) const + { + // prepare fill polyPolygon with given pattern, check for patternTransform + if(rFillPattern.getPatternTransform() && !rFillPattern.getPatternTransform()->isIdentity()) + { + // PatternTransform is active; Handle by filling the inverse transformed + // path and back-transforming the result + basegfx::B2DPolyPolygon aPath(rPath); + basegfx::B2DHomMatrix aInv(*rFillPattern.getPatternTransform()); + drawinglayer::primitive2d::Primitive2DSequence aNewTarget; + + aInv.invert(); + aPath.transform(aInv); + add_fillPattern(aPath, aNewTarget, rFillPattern, aPath.getB2DRange()); + + if(aNewTarget.hasElements()) + { + drawinglayer::primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence( + rTarget, + new drawinglayer::primitive2d::TransformPrimitive2D( + *rFillPattern.getPatternTransform(), + aNewTarget)); + } + } + else + { + // no patternTransform, create fillPattern directly + add_fillPattern(rPath, rTarget, rFillPattern, rGeoRange); + } + } + + void SvgStyleAttributes::add_fillPattern( + const basegfx::B2DPolyPolygon& rPath, + drawinglayer::primitive2d::Primitive2DSequence& rTarget, + const SvgPatternNode& rFillPattern, + const basegfx::B2DRange& rGeoRange) const + { + // fill polyPolygon with given pattern + const drawinglayer::primitive2d::Primitive2DSequence& rPrimitives = rFillPattern.getPatternPrimitives(); + + if(rPrimitives.hasElements()) + { + double fTargetWidth(rGeoRange.getWidth()); + double fTargetHeight(rGeoRange.getHeight()); + + if(fTargetWidth > 0.0 && fTargetHeight > 0.0) + { + // get relative values from pattern + double fX(0.0); + double fY(0.0); + double fW(0.0); + double fH(0.0); + + rFillPattern.getValuesRelative(fX, fY, fW, fH, rGeoRange, mrOwner); + + if(fW > 0.0 && fH > 0.0) + { + // build the reference range relative to the rGeoRange + const basegfx::B2DRange aReferenceRange(fX, fY, fX + fW, fY + fH); + + // find out how the content is mapped to the reference range + basegfx::B2DHomMatrix aMapPrimitivesToUnitRange; + const basegfx::B2DRange* pViewBox = rFillPattern.getViewBox(); + + if(pViewBox) + { + // use viewBox/preserveAspectRatio + const SvgAspectRatio& rRatio = rFillPattern.getSvgAspectRatio(); + const basegfx::B2DRange aUnitRange(0.0, 0.0, 1.0, 1.0); + + if(rRatio.isSet()) + { + // let mapping be created from SvgAspectRatio + aMapPrimitivesToUnitRange = rRatio.createMapping(aUnitRange, *pViewBox); + } + else + { + // choose default mapping + aMapPrimitivesToUnitRange = rRatio.createLinearMapping(aUnitRange, *pViewBox); + } + } + else + { + // use patternContentUnits + const SvgUnits aPatternContentUnits(rFillPattern.getPatternContentUnits() ? *rFillPattern.getPatternContentUnits() : userSpaceOnUse); + + if(userSpaceOnUse == aPatternContentUnits) + { + // create relative mapping to unit coordinates + aMapPrimitivesToUnitRange.scale(1.0 / (fW * fTargetWidth), 1.0 / (fH * fTargetHeight)); + } + else + { + aMapPrimitivesToUnitRange.scale(1.0 / fW, 1.0 / fH); + } + } + + // apply aMapPrimitivesToUnitRange to content when used + drawinglayer::primitive2d::Primitive2DSequence aPrimitives(rPrimitives); + + if(!aMapPrimitivesToUnitRange.isIdentity()) + { + const drawinglayer::primitive2d::Primitive2DReference xRef( + new drawinglayer::primitive2d::TransformPrimitive2D( + aMapPrimitivesToUnitRange, + aPrimitives)); + + aPrimitives = drawinglayer::primitive2d::Primitive2DSequence(&xRef, 1); + } + + // embed in PatternFillPrimitive2D + drawinglayer::primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence( + rTarget, + new drawinglayer::primitive2d::PatternFillPrimitive2D( + rPath, + aPrimitives, + aReferenceRange)); + } + } + } + } + + void SvgStyleAttributes::add_fill( + const basegfx::B2DPolyPolygon& rPath, + drawinglayer::primitive2d::Primitive2DSequence& rTarget, + const basegfx::B2DRange& rGeoRange) const + { + const basegfx::BColor* pFill = getFill(); + const SvgGradientNode* pFillGradient = getSvgGradientNodeFill(); + const SvgPatternNode* pFillPattern = getSvgPatternNodeFill(); + + if(pFill || pFillGradient || pFillPattern) + { + const double fFillOpacity(getFillOpacity().solve(mrOwner, length)); + + if(basegfx::fTools::more(fFillOpacity, 0.0)) + { + drawinglayer::primitive2d::Primitive2DSequence aNewFill; + + if(pFillGradient) + { + // create fill content with SVG gradient primitive + add_fillGradient(rPath, aNewFill, *pFillGradient, rGeoRange); + } + else if(pFillPattern) + { + // create fill content with SVG pattern primitive + add_fillPatternTransform(rPath, aNewFill, *pFillPattern, rGeoRange); + } + else // if(pFill) + { + // create fill content + aNewFill.realloc(1); + aNewFill[0] = new drawinglayer::primitive2d::PolyPolygonColorPrimitive2D( + rPath, + *pFill); + } + + if(aNewFill.hasElements()) + { + if(basegfx::fTools::less(fFillOpacity, 1.0)) + { + // embed in UnifiedTransparencePrimitive2D + drawinglayer::primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence( + rTarget, + new drawinglayer::primitive2d::UnifiedTransparencePrimitive2D( + aNewFill, + 1.0 - fFillOpacity)); + } + else + { + // append + drawinglayer::primitive2d::appendPrimitive2DSequenceToPrimitive2DSequence(rTarget, aNewFill); + } + } + } + } + } + + void SvgStyleAttributes::add_stroke( + const basegfx::B2DPolyPolygon& rPath, + drawinglayer::primitive2d::Primitive2DSequence& rTarget, + const basegfx::B2DRange& rGeoRange) const + { + const basegfx::BColor* pStroke = getStroke(); + const SvgGradientNode* pStrokeGradient = getSvgGradientNodeStroke(); + const SvgPatternNode* pStrokePattern = getSvgPatternNodeStroke(); + + if(pStroke || pStrokeGradient || pStrokePattern) + { + drawinglayer::primitive2d::Primitive2DSequence aNewStroke; + const double fStrokeOpacity(getStrokeOpacity().solve(mrOwner, length)); + + if(basegfx::fTools::more(fStrokeOpacity, 0.0)) + { + // get stroke width; SVG does not use 0.0 == hairline, so 0.0 is no line at all + const double fStrokeWidth(getStrokeWidth().isSet() ? getStrokeWidth().solve(mrOwner, length) : 1.0); + + if(basegfx::fTools::more(fStrokeWidth, 0.0)) + { + // get LineJoin, LineCap and stroke array + const basegfx::B2DLineJoin aB2DLineJoin(StrokeLinejoinToB2DLineJoin(getStrokeLinejoin())); + const com::sun::star::drawing::LineCap aLineCap(StrokeLinecapToDrawingLineCap(getStrokeLinecap())); + ::std::vector< double > aDashArray; + + if(!getStrokeDasharray().empty()) + { + aDashArray = solveSvgNumberVector(getStrokeDasharray(), mrOwner, length); + } + + // todo: Handle getStrokeDashOffset() + + // prepare line attribute + drawinglayer::primitive2d::Primitive2DReference aNewLinePrimitive; + const drawinglayer::attribute::LineAttribute aLineAttribute( + pStroke ? *pStroke : basegfx::BColor(0.0, 0.0, 0.0), + fStrokeWidth, + aB2DLineJoin, + aLineCap); + + if(aDashArray.empty()) + { + aNewLinePrimitive = new drawinglayer::primitive2d::PolyPolygonStrokePrimitive2D( + rPath, + aLineAttribute); + } + else + { + const drawinglayer::attribute::StrokeAttribute aStrokeAttribute(aDashArray); + + aNewLinePrimitive = new drawinglayer::primitive2d::PolyPolygonStrokePrimitive2D( + rPath, + aLineAttribute, + aStrokeAttribute); + } + + if(pStrokeGradient || pStrokePattern) + { + // put primitive into Primitive2DReference and Primitive2DSequence + const drawinglayer::primitive2d::Primitive2DSequence aSeq(&aNewLinePrimitive, 1); + + // use neutral ViewInformation and create LineGeometryExtractor2D + const drawinglayer::geometry::ViewInformation2D aViewInformation2D; + drawinglayer::processor2d::LineGeometryExtractor2D aExtractor(aViewInformation2D); + + // proccess + aExtractor.process(aSeq); + + // check for fill rsults + const basegfx::B2DPolyPolygonVector& rLineFillVector(aExtractor.getExtractedLineFills()); + + if(!rLineFillVector.empty()) + { + const basegfx::B2DPolyPolygon aMergedArea( + basegfx::tools::mergeToSinglePolyPolygon( + rLineFillVector)); + + if(aMergedArea.count()) + { + if(pStrokeGradient) + { + // create fill content with SVG gradient primitive. Use original GeoRange, + // e.g. from circle without LineWidth + add_fillGradient(aMergedArea, aNewStroke, *pStrokeGradient, rGeoRange); + } + else // if(pStrokePattern) + { + // create fill content with SVG pattern primitive. Use GeoRange + // from the expanded data, e.g. circle with extended geo by half linewidth + add_fillPatternTransform(aMergedArea, aNewStroke, *pStrokePattern, aMergedArea.getB2DRange()); + } + } + } + } + else // if(pStroke) + { + drawinglayer::primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(aNewStroke, aNewLinePrimitive); + } + + if(aNewStroke.hasElements()) + { + if(basegfx::fTools::less(fStrokeOpacity, 1.0)) + { + // embed in UnifiedTransparencePrimitive2D + drawinglayer::primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence( + rTarget, + new drawinglayer::primitive2d::UnifiedTransparencePrimitive2D( + aNewStroke, + 1.0 - fStrokeOpacity)); + } + else + { + // append + drawinglayer::primitive2d::appendPrimitive2DSequenceToPrimitive2DSequence(rTarget, aNewStroke); + } + } + } + } + } + } + + double get_markerRotation( + const SvgMarkerNode& rMarker, + const basegfx::B2DPolygon& rPolygon, + const sal_uInt32 nIndex) + { + double fAngle(0.0); + const sal_uInt32 nPointCount(rPolygon.count()); + + if(nPointCount) + { + if(rMarker.getOrientAuto()) + { + const bool bPrev(rPolygon.isClosed() || nIndex > 0); + basegfx::B2DCubicBezier aSegment; + basegfx::B2DVector aPrev; + basegfx::B2DVector aNext; + + if(bPrev) + { + rPolygon.getBezierSegment((nIndex - 1) % nPointCount, aSegment); + aPrev = aSegment.getTangent(1.0); + } + + const bool bNext(rPolygon.isClosed() || nIndex + 1 < nPointCount); + + if(bNext) + { + rPolygon.getBezierSegment(nIndex % nPointCount, aSegment); + aNext = aSegment.getTangent(0.0); + } + + if(bPrev && bNext) + { + fAngle = atan2(aPrev.getY() + aNext.getY(), aPrev.getX() + aNext.getX()); + } + else if(bPrev) + { + fAngle = atan2(aPrev.getY(), aPrev.getX()); + } + else if(bNext) + { + fAngle = atan2(aNext.getY(), aNext.getX()); + } + } + else + { + fAngle = rMarker.getAngle(); + } + } + + return fAngle; + } + + bool SvgStyleAttributes::prepare_singleMarker( + drawinglayer::primitive2d::Primitive2DSequence& rMarkerPrimitives, + basegfx::B2DHomMatrix& rMarkerTransform, + basegfx::B2DRange& rClipRange, + const SvgMarkerNode& rMarker) const + { + // reset return values + rMarkerTransform.identity(); + rClipRange.reset(); + + // get marker primitive representation + rMarkerPrimitives = rMarker.getMarkerPrimitives(); + + if(rMarkerPrimitives.hasElements()) + { + basegfx::B2DRange aPrimitiveRange(0.0, 0.0, 1.0, 1.0); + const basegfx::B2DRange* pViewBox = rMarker.getViewBox(); + + if(pViewBox) + { + aPrimitiveRange = *pViewBox; + } + + if(aPrimitiveRange.getWidth() > 0.0 && aPrimitiveRange.getHeight() > 0.0) + { + double fTargetWidth(rMarker.getMarkerWidth().isSet() ? rMarker.getMarkerWidth().solve(mrOwner, xcoordinate) : 3.0); + double fTargetHeight(rMarker.getMarkerHeight().isSet() ? rMarker.getMarkerHeight().solve(mrOwner, xcoordinate) : 3.0); + const bool bStrokeWidth(SvgMarkerNode::strokeWidth == rMarker.getMarkerUnits()); + const double fStrokeWidth(getStrokeWidth().isSet() ? getStrokeWidth().solve(mrOwner, length) : 1.0); + + if(bStrokeWidth) + { + // relative to strokeWidth + fTargetWidth *= fStrokeWidth; + fTargetHeight *= fStrokeWidth; + } + + if(fTargetWidth > 0.0 && fTargetHeight > 0.0) + { + // create mapping + const basegfx::B2DRange aTargetRange(0.0, 0.0, fTargetWidth, fTargetHeight); + const SvgAspectRatio& rRatio = rMarker.getSvgAspectRatio(); + + if(rRatio.isSet()) + { + // let mapping be created from SvgAspectRatio + rMarkerTransform = rRatio.createMapping(aTargetRange, aPrimitiveRange); + + if(rRatio.isMeetOrSlice()) + { + // need to clip + rClipRange = aPrimitiveRange; + } + } + else + { + if(!pViewBox) + { + if(bStrokeWidth) + { + // adapt to strokewidth if needed + rMarkerTransform.scale(fStrokeWidth, fStrokeWidth); + } + } + else + { + // choose default mapping + rMarkerTransform = rRatio.createLinearMapping(aTargetRange, aPrimitiveRange); + } + } + + // get and apply reference point. Initially it's in marker local coordinate system + basegfx::B2DPoint aRefPoint( + rMarker.getRefX().isSet() ? rMarker.getRefX().solve(mrOwner, xcoordinate) : 0.0, + rMarker.getRefY().isSet() ? rMarker.getRefY().solve(mrOwner, ycoordinate) : 0.0); + + // apply MarkerTransform to have it in mapped coordinates + aRefPoint *= rMarkerTransform; + + // apply by moving RepPoint to (0.0) + rMarkerTransform.translate(-aRefPoint.getX(), -aRefPoint.getY()); + + return true; + } + } + } + + return false; + } + + void SvgStyleAttributes::add_singleMarker( + drawinglayer::primitive2d::Primitive2DSequence& rTarget, + const drawinglayer::primitive2d::Primitive2DSequence& rMarkerPrimitives, + const basegfx::B2DHomMatrix& rMarkerTransform, + const basegfx::B2DRange& rClipRange, + const SvgMarkerNode& rMarker, + const basegfx::B2DPolygon& rCandidate, + const sal_uInt32 nIndex) const + { + const sal_uInt32 nPointCount(rCandidate.count()); + + if(nPointCount) + { + // get and apply rotation + basegfx::B2DHomMatrix aCombinedTransform(rMarkerTransform); + aCombinedTransform.rotate(get_markerRotation(rMarker, rCandidate, nIndex)); + + // get and apply target position + const basegfx::B2DPoint aPoint(rCandidate.getB2DPoint(nIndex % nPointCount)); + aCombinedTransform.translate(aPoint.getX(), aPoint.getY()); + + // prepare marker + drawinglayer::primitive2d::Primitive2DReference xMarker( + new drawinglayer::primitive2d::TransformPrimitive2D( + aCombinedTransform, + rMarkerPrimitives)); + + if(!rClipRange.isEmpty()) + { + // marker needs to be clipped, it's bigger as the mapping + basegfx::B2DPolyPolygon aClipPolygon(basegfx::tools::createPolygonFromRect(rClipRange)); + + aClipPolygon.transform(aCombinedTransform); + xMarker = new drawinglayer::primitive2d::MaskPrimitive2D( + aClipPolygon, + drawinglayer::primitive2d::Primitive2DSequence(&xMarker, 1)); + } + + // add marker + drawinglayer::primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(rTarget, xMarker); + } + } + + void SvgStyleAttributes::add_markers( + const basegfx::B2DPolyPolygon& rPath, + drawinglayer::primitive2d::Primitive2DSequence& rTarget) const + { + // try to access linked markers + const SvgMarkerNode* pStart = accessMarkerStartXLink(); + const SvgMarkerNode* pMid = accessMarkerMidXLink(); + const SvgMarkerNode* pEnd = accessMarkerEndXLink(); + + if(pStart || pMid || pEnd) + { + const sal_uInt32 nCount(rPath.count()); + + for (sal_uInt32 a(0); a < nCount; a++) + { + const basegfx::B2DPolygon aCandidate(rPath.getB2DPolygon(a)); + const sal_uInt32 nPointCount(aCandidate.count()); + + if(nPointCount) + { + const sal_uInt32 nMarkerCount(aCandidate.isClosed() ? nPointCount + 1 : nPointCount); + drawinglayer::primitive2d::Primitive2DSequence aMarkerPrimitives; + basegfx::B2DHomMatrix aMarkerTransform; + basegfx::B2DRange aClipRange; + const SvgMarkerNode* pPrepared = 0; + + if(pStart) + { + if(prepare_singleMarker(aMarkerPrimitives, aMarkerTransform, aClipRange, *pStart)) + { + pPrepared = pStart; + add_singleMarker(rTarget, aMarkerPrimitives, aMarkerTransform, aClipRange, *pPrepared, aCandidate, 0); + } + } + + if(pMid && nMarkerCount > 2) + { + if(pMid == pPrepared || prepare_singleMarker(aMarkerPrimitives, aMarkerTransform, aClipRange, *pMid)) + { + pPrepared = pMid; + + for(sal_uInt32 b(1); b < nMarkerCount - 1; b++) + { + add_singleMarker(rTarget, aMarkerPrimitives, aMarkerTransform, aClipRange, *pPrepared, aCandidate, b); + } + } + } + + if(pEnd) + { + if(pEnd == pPrepared || prepare_singleMarker(aMarkerPrimitives, aMarkerTransform, aClipRange, *pEnd)) + { + pPrepared = pEnd; + add_singleMarker(rTarget, aMarkerPrimitives, aMarkerTransform, aClipRange, *pPrepared, aCandidate, nMarkerCount - 1); + } + } + } + } + } + } + + void SvgStyleAttributes::add_path( + const basegfx::B2DPolyPolygon& rPath, + drawinglayer::primitive2d::Primitive2DSequence& rTarget) const + { + const bool bIsLine(1 == rPath.count() + && !rPath.areControlPointsUsed() + && 2 == rPath.getB2DPolygon(0).count()); + + if(!rPath.count()) + { + return; + } + + const basegfx::B2DRange aGeoRange(rPath.getB2DRange()); + + if(aGeoRange.isEmpty()) + { + return; + } + + if(!bIsLine && // not for lines + (basegfx::fTools::equalZero(aGeoRange.getWidth()) + || basegfx::fTools::equalZero(aGeoRange.getHeight()))) + { + return; + } + + const double fOpacity(getOpacity().getNumber()); + + if(basegfx::fTools::equalZero(fOpacity)) + { + return; + } + + if(!bIsLine) + { + basegfx::B2DPolyPolygon aPath(rPath); + const bool bNeedToCheckClipRule(SVGTokenPath == mrOwner.getType() || SVGTokenPolygon == mrOwner.getType()); + const bool bClipPathIsNonzero(!bIsLine && bNeedToCheckClipRule && mbIsClipPathContent && mbClipRule); + const bool bFillRuleIsNonzero(!bIsLine && bNeedToCheckClipRule && !mbIsClipPathContent && getFillRule()); + + if(bClipPathIsNonzero || bFillRuleIsNonzero) + { + // nonzero is wanted, solve geometrically (see description on basegfx) + aPath = basegfx::tools::createNonzeroConform(aPath); + } + + add_fill(aPath, rTarget, aGeoRange); + } + + add_stroke(rPath, rTarget, aGeoRange); + + // Svg supports markers for path, polygon, polyline and line + if(SVGTokenPath == mrOwner.getType() || // path + SVGTokenPolygon == mrOwner.getType() || // polygon, polyline + SVGTokenLine == mrOwner.getType()) // line + { + // try to add markers + add_markers(rPath, rTarget); + } + } + + void SvgStyleAttributes::add_postProcess( + drawinglayer::primitive2d::Primitive2DSequence& rTarget, + const drawinglayer::primitive2d::Primitive2DSequence& rSource, + const basegfx::B2DHomMatrix* pTransform) const + { + if(rSource.hasElements()) + { + const double fOpacity(getOpacity().getNumber()); + + if(basegfx::fTools::equalZero(fOpacity)) + { + return; + } + + drawinglayer::primitive2d::Primitive2DSequence aSource(rSource); + + if(basegfx::fTools::less(fOpacity, 1.0)) + { + // embed in UnifiedTransparencePrimitive2D + const drawinglayer::primitive2d::Primitive2DReference xRef( + new drawinglayer::primitive2d::UnifiedTransparencePrimitive2D( + aSource, + 1.0 - fOpacity)); + + aSource = drawinglayer::primitive2d::Primitive2DSequence(&xRef, 1); + } + + if(getClipPathXLink().getLength()) + { + // try to access linked ClipPath + const SvgClipPathNode* mpClip = dynamic_cast< const SvgClipPathNode* >(mrOwner.getDocument().findSvgNodeById(getClipPathXLink())); + + if(mpClip) + { + mpClip->apply(aSource); + } + } + + if(aSource.hasElements()) // test again, applied clipPath may have lead to empty geometry + { + if(getMaskXLink().getLength()) + { + // try to access linked Mask + const SvgMaskNode* mpMask = dynamic_cast< const SvgMaskNode* >(mrOwner.getDocument().findSvgNodeById(getMaskXLink())); + + if(mpMask) + { + mpMask->apply(aSource); + } + } + + if(aSource.hasElements()) // test again, applied mask may have lead to empty geometry + { + if(pTransform) + { + // create embedding group element with transformation + const drawinglayer::primitive2d::Primitive2DReference xRef( + new drawinglayer::primitive2d::TransformPrimitive2D( + *pTransform, + aSource)); + + aSource = drawinglayer::primitive2d::Primitive2DSequence(&xRef, 1); + } + + // append to current target + drawinglayer::primitive2d::appendPrimitive2DSequenceToPrimitive2DSequence(rTarget, aSource); + } + } + } + } + + SvgStyleAttributes::SvgStyleAttributes(SvgNode& rOwner) + : mrOwner(rOwner), + mpCssStyleParent(0), + maFill(), + maStroke(), + maStopColor(basegfx::BColor(0.0, 0.0, 0.0), true), + maStrokeWidth(), + maStopOpacity(), + mpSvgGradientNodeFill(0), + mpSvgGradientNodeStroke(0), + mpSvgPatternNodeFill(0), + mpSvgPatternNodeStroke(0), + maFillOpacity(), + maStrokeDasharray(), + maStrokeDashOffset(), + maStrokeLinecap(StrokeLinecap_notset), + maStrokeLinejoin(StrokeLinejoin_notset), + maStrokeMiterLimit(), + maStrokeOpacity(), + maFontFamily(), + maFontSize(), + maFontStretch(FontStretch_notset), + maFontStyle(FontStyle_notset), + maFontVariant(FontVariant_notset), + maFontWeight(FontWeight_notset), + maTextAlign(TextAlign_notset), + maTextDecoration(TextDecoration_notset), + maTextAnchor(TextAnchor_notset), + maColor(), + maOpacity(1.0), + maClipPathXLink(), + maMaskXLink(), + maMarkerStartXLink(), + mpMarkerStartXLink(0), + maMarkerMidXLink(), + mpMarkerMidXLink(0), + maMarkerEndXLink(), + mpMarkerEndXLink(0), + maFillRule(true), + maFillRuleSet(false), + mbIsClipPathContent(SVGTokenClipPathNode == mrOwner.getType()), + mbClipRule(true) + { + if(!mbIsClipPathContent) + { + const SvgStyleAttributes* pParentStyle = getParentStyle(); + + if(pParentStyle) + { + mbIsClipPathContent = pParentStyle->mbIsClipPathContent; + } + } + } + + SvgStyleAttributes::~SvgStyleAttributes() + { + } + + void SvgStyleAttributes::parseStyleAttribute(const rtl::OUString& /*rTokenName*/, SVGToken aSVGToken, const rtl::OUString& aContent) + { + switch(aSVGToken) + { + case SVGTokenFill: + { + SvgPaint aSvgPaint; + rtl::OUString aURL; + + if(readSvgPaint(aContent, aSvgPaint, aURL)) + { + setFill(aSvgPaint); + } + else if(aURL.getLength()) + { + const SvgNode* pNode = mrOwner.getDocument().findSvgNodeById(aURL); + + if(pNode) + { + if(SVGTokenLinearGradient == pNode->getType() || SVGTokenRadialGradient == pNode->getType()) + { + setSvgGradientNodeFill(static_cast< const SvgGradientNode* >(pNode)); + } + else if(SVGTokenPattern == pNode->getType()) + { + setSvgPatternNodeFill(static_cast< const SvgPatternNode* >(pNode)); + } + } + } + break; + } + case SVGTokenFillOpacity: + { + SvgNumber aNum; + + if(readSingleNumber(aContent, aNum)) + { + if(aNum.isPositive()) + { + setFillOpacity(aNum); + } + } + break; + } + case SVGTokenFillRule: + { + if(aContent.getLength()) + { + if(aContent.match(commonStrings::aStrNonzero)) + { + maFillRule = true; + maFillRuleSet = true; + } + else if(aContent.match(commonStrings::aStrEvenOdd)) + { + maFillRule = false; + maFillRuleSet = true; + } + } + break; + } + case SVGTokenStroke: + { + SvgPaint aSvgPaint; + rtl::OUString aURL; + + if(readSvgPaint(aContent, aSvgPaint, aURL)) + { + setStroke(aSvgPaint); + } + else if(aURL.getLength()) + { + const SvgNode* pNode = mrOwner.getDocument().findSvgNodeById(aURL); + + if(pNode) + { + if(SVGTokenLinearGradient == pNode->getType() || SVGTokenRadialGradient == pNode->getType()) + { + setSvgGradientNodeStroke(static_cast< const SvgGradientNode* >(pNode)); + } + else if(SVGTokenPattern == pNode->getType()) + { + setSvgPatternNodeStroke(static_cast< const SvgPatternNode* >(pNode)); + } + } + } + break; + } + case SVGTokenStrokeDasharray: + { + if(aContent.getLength()) + { + SvgNumberVector aVector; + + if(readSvgNumberVector(aContent, aVector)) + { + setStrokeDasharray(aVector); + } + } + break; + } + case SVGTokenStrokeDashoffset: + { + SvgNumber aNum; + + if(readSingleNumber(aContent, aNum)) + { + if(aNum.isPositive()) + { + setStrokeDashOffset(aNum); + } + } + break; + } + case SVGTokenStrokeLinecap: + { + if(aContent.getLength()) + { + static rtl::OUString aStrButt(rtl::OUString::createFromAscii("butt")); + static rtl::OUString aStrRound(rtl::OUString::createFromAscii("round")); + static rtl::OUString aStrSquare(rtl::OUString::createFromAscii("square")); + + if(aContent.match(aStrButt)) + { + setStrokeLinecap(StrokeLinecap_butt); + } + else if(aContent.match(aStrRound)) + { + setStrokeLinecap(StrokeLinecap_round); + } + else if(aContent.match(aStrSquare)) + { + setStrokeLinecap(StrokeLinecap_square); + } + } + break; + } + case SVGTokenStrokeLinejoin: + { + if(aContent.getLength()) + { + static rtl::OUString aStrMiter(rtl::OUString::createFromAscii("miter")); + static rtl::OUString aStrRound(rtl::OUString::createFromAscii("round")); + static rtl::OUString aStrBevel(rtl::OUString::createFromAscii("bevel")); + + if(aContent.match(aStrMiter)) + { + setStrokeLinejoin(StrokeLinejoin_miter); + } + else if(aContent.match(aStrRound)) + { + setStrokeLinejoin(StrokeLinejoin_round); + } + else if(aContent.match(aStrBevel)) + { + setStrokeLinejoin(StrokeLinejoin_bevel); + } + } + break; + } + case SVGTokenStrokeMiterlimit: + { + SvgNumber aNum; + + if(readSingleNumber(aContent, aNum)) + { + if(aNum.isPositive()) + { + setStrokeMiterLimit(aNum); + } + } + break; + } + case SVGTokenStrokeOpacity: + { + SvgNumber aNum; + + if(readSingleNumber(aContent, aNum)) + { + if(aNum.isPositive()) + { + setStrokeOpacity(aNum); + } + } + break; + } + case SVGTokenStrokeWidth: + { + SvgNumber aNum; + + if(readSingleNumber(aContent, aNum)) + { + if(aNum.isPositive()) + { + setStrokeWidth(aNum); + } + } + break; + } + case SVGTokenStopColor: + { + SvgPaint aSvgPaint; + rtl::OUString aURL; + + if(readSvgPaint(aContent, aSvgPaint, aURL)) + { + setStopColor(aSvgPaint); + } + break; + } + case SVGTokenStopOpacity: + { + SvgNumber aNum; + + if(readSingleNumber(aContent, aNum)) + { + if(aNum.isPositive()) + { + setStopOpacity(aNum); + } + } + break; + } + case SVGTokenFont: + { + break; + } + case SVGTokenFontFamily: + { + SvgStringVector aSvgStringVector; + + if(readSvgStringVector(aContent, aSvgStringVector)) + { + setFontFamily(aSvgStringVector); + } + break; + } + case SVGTokenFontSize: + { + SvgNumber aNum; + + if(readSingleNumber(aContent, aNum)) + { + setFontSize(aNum); + } + break; + } + case SVGTokenFontSizeAdjust: + { + break; + } + case SVGTokenFontStretch: + { + if(aContent.getLength()) + { + static rtl::OUString aStrNormal(rtl::OUString::createFromAscii("normal")); + static rtl::OUString aStrWider(rtl::OUString::createFromAscii("wider")); + static rtl::OUString aStrNarrower(rtl::OUString::createFromAscii("narrower")); + static rtl::OUString aStrUltra_condensed(rtl::OUString::createFromAscii("ultra-condensed")); + static rtl::OUString aStrExtra_condensed(rtl::OUString::createFromAscii("extra-condensed")); + static rtl::OUString aStrCondensed(rtl::OUString::createFromAscii("condensed")); + static rtl::OUString aStrSemi_condensed(rtl::OUString::createFromAscii("semi-condensed")); + static rtl::OUString aStrSemi_expanded(rtl::OUString::createFromAscii("semi-expanded")); + static rtl::OUString aStrExpanded(rtl::OUString::createFromAscii("expanded")); + static rtl::OUString aStrExtra_expanded(rtl::OUString::createFromAscii("extra-expanded")); + static rtl::OUString aStrUltra_expanded(rtl::OUString::createFromAscii("ultra-expanded")); + + if(aContent.match(aStrNormal)) + { + setFontStretch(FontStretch_normal); + } + else if(aContent.match(aStrWider)) + { + setFontStretch(FontStretch_wider); + } + else if(aContent.match(aStrNarrower)) + { + setFontStretch(FontStretch_narrower); + } + else if(aContent.match(aStrUltra_condensed)) + { + setFontStretch(FontStretch_ultra_condensed); + } + else if(aContent.match(aStrExtra_condensed)) + { + setFontStretch(FontStretch_extra_condensed); + } + else if(aContent.match(aStrCondensed)) + { + setFontStretch(FontStretch_condensed); + } + else if(aContent.match(aStrSemi_condensed)) + { + setFontStretch(FontStretch_semi_condensed); + } + else if(aContent.match(aStrSemi_expanded)) + { + setFontStretch(FontStretch_semi_expanded); + } + else if(aContent.match(aStrExpanded)) + { + setFontStretch(FontStretch_expanded); + } + else if(aContent.match(aStrExtra_expanded)) + { + setFontStretch(FontStretch_extra_expanded); + } + else if(aContent.match(aStrUltra_expanded)) + { + setFontStretch(FontStretch_ultra_expanded); + } + } + break; + } + case SVGTokenFontStyle: + { + if(aContent.getLength()) + { + static rtl::OUString aStrNormal(rtl::OUString::createFromAscii("normal")); + static rtl::OUString aStrItalic(rtl::OUString::createFromAscii("italic")); + static rtl::OUString aStrOblique(rtl::OUString::createFromAscii("oblique")); + + if(aContent.match(aStrNormal)) + { + setFontStyle(FontStyle_normal); + } + else if(aContent.match(aStrItalic)) + { + setFontStyle(FontStyle_italic); + } + else if(aContent.match(aStrOblique)) + { + setFontStyle(FontStyle_oblique); + } + } + break; + } + case SVGTokenFontVariant: + { + if(aContent.getLength()) + { + static rtl::OUString aStrNormal(rtl::OUString::createFromAscii("normal")); + static rtl::OUString aStrSmallCaps(rtl::OUString::createFromAscii("small-caps")); + + if(aContent.match(aStrNormal)) + { + setFontVariant(FontVariant_normal); + } + else if(aContent.match(aStrSmallCaps)) + { + setFontVariant(FontVariant_small_caps); + } + } + break; + } + case SVGTokenFontWeight: + { + if(aContent.getLength()) + { + static rtl::OUString aStrNormal(rtl::OUString::createFromAscii("normal")); + static rtl::OUString aStrBold(rtl::OUString::createFromAscii("bold")); + static rtl::OUString aStrBolder(rtl::OUString::createFromAscii("bolder")); + static rtl::OUString aStrLighter(rtl::OUString::createFromAscii("lighter")); + static rtl::OUString aStr100(rtl::OUString::createFromAscii("100")); + static rtl::OUString aStr200(rtl::OUString::createFromAscii("200")); + static rtl::OUString aStr300(rtl::OUString::createFromAscii("300")); + static rtl::OUString aStr400(rtl::OUString::createFromAscii("400")); + static rtl::OUString aStr500(rtl::OUString::createFromAscii("500")); + static rtl::OUString aStr600(rtl::OUString::createFromAscii("600")); + static rtl::OUString aStr700(rtl::OUString::createFromAscii("700")); + static rtl::OUString aStr800(rtl::OUString::createFromAscii("800")); + static rtl::OUString aStr900(rtl::OUString::createFromAscii("900")); + + if(aContent.match(aStr100)) + { + setFontWeight(FontWeight_100); + } + else if(aContent.match(aStr200)) + { + setFontWeight(FontWeight_200); + } + else if(aContent.match(aStr300)) + { + setFontWeight(FontWeight_300); + } + else if(aContent.match(aStr400) || aContent.match(aStrNormal)) + { + setFontWeight(FontWeight_400); + } + else if(aContent.match(aStr500)) + { + setFontWeight(FontWeight_500); + } + else if(aContent.match(aStr600)) + { + setFontWeight(FontWeight_600); + } + else if(aContent.match(aStr700) || aContent.match(aStrBold)) + { + setFontWeight(FontWeight_700); + } + else if(aContent.match(aStr800)) + { + setFontWeight(FontWeight_800); + } + else if(aContent.match(aStr900)) + { + setFontWeight(FontWeight_900); + } + else if(aContent.match(aStrBolder)) + { + setFontWeight(FontWeight_bolder); + } + else if(aContent.match(aStrLighter)) + { + setFontWeight(FontWeight_lighter); + } + } + break; + } + case SVGTokenDirection: + { + break; + } + case SVGTokenLetterSpacing: + { + break; + } + case SVGTokenTextDecoration: + { + if(aContent.getLength()) + { + static rtl::OUString aStrNone(rtl::OUString::createFromAscii("none")); + static rtl::OUString aStrUnderline(rtl::OUString::createFromAscii("underline")); + static rtl::OUString aStrOverline(rtl::OUString::createFromAscii("overline")); + static rtl::OUString aStrLineThrough(rtl::OUString::createFromAscii("line-through")); + static rtl::OUString aStrBlink(rtl::OUString::createFromAscii("blink")); + + if(aContent.match(aStrNone)) + { + setTextDecoration(TextDecoration_none); + } + else if(aContent.match(aStrUnderline)) + { + setTextDecoration(TextDecoration_underline); + } + else if(aContent.match(aStrOverline)) + { + setTextDecoration(TextDecoration_overline); + } + else if(aContent.match(aStrLineThrough)) + { + setTextDecoration(TextDecoration_line_through); + } + else if(aContent.match(aStrBlink)) + { + setTextDecoration(TextDecoration_blink); + } + } + break; + } + case SVGTokenUnicodeBidi: + { + break; + } + case SVGTokenWordSpacing: + { + break; + } + case SVGTokenTextAnchor: + { + if(aContent.getLength()) + { + static rtl::OUString aStrStart(rtl::OUString::createFromAscii("start")); + static rtl::OUString aStrMiddle(rtl::OUString::createFromAscii("middle")); + static rtl::OUString aStrEnd(rtl::OUString::createFromAscii("end")); + + if(aContent.match(aStrStart)) + { + setTextAnchor(TextAnchor_start); + } + else if(aContent.match(aStrMiddle)) + { + setTextAnchor(TextAnchor_middle); + } + else if(aContent.match(aStrEnd)) + { + setTextAnchor(TextAnchor_end); + } + } + break; + } + case SVGTokenTextAlign: + { + if(aContent.getLength()) + { + static rtl::OUString aStrLeft(rtl::OUString::createFromAscii("left")); + static rtl::OUString aStrRight(rtl::OUString::createFromAscii("right")); + static rtl::OUString aStrCenter(rtl::OUString::createFromAscii("center")); + static rtl::OUString aStrJustify(rtl::OUString::createFromAscii("justify")); + + if(aContent.match(aStrLeft)) + { + setTextAlign(TextAlign_left); + } + else if(aContent.match(aStrRight)) + { + setTextAlign(TextAlign_right); + } + else if(aContent.match(aStrCenter)) + { + setTextAlign(TextAlign_center); + } + else if(aContent.match(aStrJustify)) + { + setTextAlign(TextAlign_justify); + } + } + break; + } + case SVGTokenColor: + { + SvgPaint aSvgPaint; + rtl::OUString aURL; + + if(readSvgPaint(aContent, aSvgPaint, aURL)) + { + setColor(aSvgPaint); + } + break; + } + case SVGTokenOpacity: + { + SvgNumber aNum; + + if(readSingleNumber(aContent, aNum)) + { + setOpacity(SvgNumber(basegfx::clamp(aNum.getNumber(), 0.0, 1.0), aNum.getUnit(), aNum.isSet())); + } + break; + } + case SVGTokenClipPathProperty: + { + readLocalUrl(aContent, maClipPathXLink); + break; + } + case SVGTokenMask: + { + readLocalUrl(aContent, maMaskXLink); + break; + } + case SVGTokenClipRule: + { + if(aContent.getLength()) + { + if(aContent.match(commonStrings::aStrNonzero)) + { + mbClipRule = true; + } + else if(aContent.match(commonStrings::aStrEvenOdd)) + { + mbClipRule = false; + } + } + break; + } + case SVGTokenMarker: + { + readLocalUrl(aContent, maMarkerEndXLink); + maMarkerStartXLink = maMarkerMidXLink = maMarkerEndXLink; + break; + } + case SVGTokenMarkerStart: + { + readLocalUrl(aContent, maMarkerStartXLink); + break; + } + case SVGTokenMarkerMid: + { + readLocalUrl(aContent, maMarkerMidXLink); + break; + } + case SVGTokenMarkerEnd: + { + readLocalUrl(aContent, maMarkerEndXLink); + break; + } + default: + { + break; + } + } + } + + const basegfx::BColor* SvgStyleAttributes::getFill() const + { + if(mbIsClipPathContent) + { + static basegfx::BColor aBlack(0.0, 0.0, 0.0); + + return &aBlack; + } + else if(maFill.isSet()) + { + if(maFill.isCurrent()) + { + return getColor(); + } + else if(maFill.isOn()) + { + return &maFill.getBColor(); + } + } + else + { + const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle(); + + if(pSvgStyleAttributes) + { + return pSvgStyleAttributes->getFill(); + } + } + + return 0; + } + + const basegfx::BColor* SvgStyleAttributes::getStroke() const + { + if(mbIsClipPathContent) + { + return 0; + } + else if(maStroke.isSet()) + { + if(maStroke.isCurrent()) + { + return getColor(); + } + else if(maStroke.isOn()) + { + return &maStroke.getBColor(); + } + } + else + { + const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle(); + + if(pSvgStyleAttributes) + { + return pSvgStyleAttributes->getStroke(); + } + } + + return 0; + } + + const basegfx::BColor& SvgStyleAttributes::getStopColor() const + { + if(maStopColor.isCurrent()) + { + return *getColor(); + } + else + { + return maStopColor.getBColor(); + } + } + + const SvgGradientNode* SvgStyleAttributes::getSvgGradientNodeFill() const + { + if(mbIsClipPathContent) + { + return 0; + } + else if(mpSvgGradientNodeFill) + { + return mpSvgGradientNodeFill; + } + else + { + const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle(); + + if(pSvgStyleAttributes) + { + return pSvgStyleAttributes->getSvgGradientNodeFill(); + } + } + + return 0; + } + + const SvgGradientNode* SvgStyleAttributes::getSvgGradientNodeStroke() const + { + if(mbIsClipPathContent) + { + return 0; + } + else if(mpSvgGradientNodeStroke) + { + return mpSvgGradientNodeStroke; + } + else + { + const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle(); + + if(pSvgStyleAttributes) + { + return pSvgStyleAttributes->getSvgGradientNodeStroke(); + } + } + + return 0; + } + + const SvgPatternNode* SvgStyleAttributes::getSvgPatternNodeFill() const + { + if(mbIsClipPathContent) + { + return 0; + } + else if(mpSvgPatternNodeFill) + { + return mpSvgPatternNodeFill; + } + else + { + const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle(); + + if(pSvgStyleAttributes) + { + return pSvgStyleAttributes->getSvgPatternNodeFill(); + } + } + + return 0; + } + + const SvgPatternNode* SvgStyleAttributes::getSvgPatternNodeStroke() const + { + if(mbIsClipPathContent) + { + return 0; + } + else if(mpSvgPatternNodeStroke) + { + return mpSvgPatternNodeStroke; + } + else + { + const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle(); + + if(pSvgStyleAttributes) + { + return pSvgStyleAttributes->getSvgPatternNodeStroke(); + } + } + + return 0; + } + + const SvgNumber SvgStyleAttributes::getStrokeWidth() const + { + if(mbIsClipPathContent) + { + return SvgNumber(0.0); + } + else if(maStrokeWidth.isSet()) + { + return maStrokeWidth; + } + + const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle(); + + if(pSvgStyleAttributes) + { + return pSvgStyleAttributes->getStrokeWidth(); + } + + // default is 1 + return SvgNumber(1.0); + } + + const SvgNumber SvgStyleAttributes::getStopOpacity() const + { + if(maStopOpacity.isSet()) + { + return maStopOpacity; + } + + // default is 1 + return SvgNumber(1.0); + } + + const SvgNumber SvgStyleAttributes::getFillOpacity() const + { + if(mbIsClipPathContent) + { + return SvgNumber(1.0); + } + else if(maFillOpacity.isSet()) + { + return maFillOpacity; + } + + const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle(); + + if(pSvgStyleAttributes) + { + return pSvgStyleAttributes->getFillOpacity(); + } + + // default is 1 + return SvgNumber(1.0); + } + + bool SvgStyleAttributes::getFillRule() const + { + if(maFillRuleSet) + { + return maFillRule; + } + + const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle(); + + if(pSvgStyleAttributes) + { + return pSvgStyleAttributes->getFillRule(); + } + + // default is NonZero + return true; + } + + void SvgStyleAttributes::setFillRule(const bool* pFillRule) + { + if(pFillRule) + { + maFillRuleSet = true; + maFillRule = *pFillRule; + } + else + { + maFillRuleSet = false; + } + } + + const SvgNumberVector& SvgStyleAttributes::getStrokeDasharray() const + { + if(!maStrokeDasharray.empty()) + { + return maStrokeDasharray; + } + + const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle(); + + if(pSvgStyleAttributes) + { + return pSvgStyleAttributes->getStrokeDasharray(); + } + + // default empty + return maStrokeDasharray; + } + + const SvgNumber SvgStyleAttributes::getStrokeDashOffset() const + { + if(maStrokeDashOffset.isSet()) + { + return maStrokeDashOffset; + } + + const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle(); + + if(pSvgStyleAttributes) + { + return pSvgStyleAttributes->getStrokeDashOffset(); + } + + // default is 0 + return SvgNumber(0.0); + } + + StrokeLinecap SvgStyleAttributes::getStrokeLinecap() const + { + if(maStrokeLinecap != StrokeLinecap_notset) + { + return maStrokeLinecap; + } + + const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle(); + + if(pSvgStyleAttributes) + { + return pSvgStyleAttributes->getStrokeLinecap(); + } + + // default is StrokeLinecap_butt + return StrokeLinecap_butt; + } + + StrokeLinejoin SvgStyleAttributes::getStrokeLinejoin() const + { + if(maStrokeLinejoin != StrokeLinejoin_notset) + { + return maStrokeLinejoin; + } + + const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle(); + + if(pSvgStyleAttributes) + { + return pSvgStyleAttributes->getStrokeLinejoin(); + } + + // default is StrokeLinejoin_butt + return StrokeLinejoin_miter; + } + + const SvgNumber SvgStyleAttributes::getStrokeMiterLimit() const + { + if(maStrokeMiterLimit.isSet()) + { + return maStrokeMiterLimit; + } + + const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle(); + + if(pSvgStyleAttributes) + { + return pSvgStyleAttributes->getStrokeMiterLimit(); + } + + // default is 4 + return SvgNumber(4.0); + } + + const SvgNumber SvgStyleAttributes::getStrokeOpacity() const + { + if(maStrokeOpacity.isSet()) + { + return maStrokeOpacity; + } + + const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle(); + + if(pSvgStyleAttributes) + { + return pSvgStyleAttributes->getStrokeOpacity(); + } + + // default is 1 + return SvgNumber(1.0); + } + + const SvgStringVector& SvgStyleAttributes::getFontFamily() const + { + if(!maFontFamily.empty()) + { + return maFontFamily; + } + + const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle(); + + if(pSvgStyleAttributes) + { + return pSvgStyleAttributes->getFontFamily(); + } + + // default is empty + return maFontFamily; + } + + const SvgNumber SvgStyleAttributes::getFontSize() const + { + if(maFontSize.isSet()) + { + return maFontSize; + } + + const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle(); + + if(pSvgStyleAttributes) + { + return pSvgStyleAttributes->getFontSize(); + } + + // default is 'medium' + return SvgNumber(12.0); + } + + FontStretch SvgStyleAttributes::getFontStretch() const + { + if(maFontStretch != FontStretch_notset) + { + if(FontStretch_wider != maFontStretch && FontStretch_narrower != maFontStretch) + { + return maFontStretch; + } + } + + const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle(); + + if(pSvgStyleAttributes) + { + FontStretch aInherited = pSvgStyleAttributes->getFontStretch(); + + if(FontStretch_wider == maFontStretch) + { + aInherited = getWider(aInherited); + } + else if(FontStretch_narrower == maFontStretch) + { + aInherited = getNarrower(aInherited); + } + + return aInherited; + } + + // default is FontStretch_normal + return FontStretch_normal; + } + + FontStyle SvgStyleAttributes::getFontStyle() const + { + if(maFontStyle != FontStyle_notset) + { + return maFontStyle; + } + + const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle(); + + if(pSvgStyleAttributes) + { + return pSvgStyleAttributes->getFontStyle(); + } + + // default is FontStyle_normal + return FontStyle_normal; + } + + FontWeight SvgStyleAttributes::getFontWeight() const + { + if(maFontWeight != FontWeight_notset) + { + if(FontWeight_bolder != maFontWeight && FontWeight_lighter != maFontWeight) + { + return maFontWeight; + } + } + + const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle(); + + if(pSvgStyleAttributes) + { + FontWeight aInherited = pSvgStyleAttributes->getFontWeight(); + + if(FontWeight_bolder == maFontWeight) + { + aInherited = getBolder(aInherited); + } + else if(FontWeight_lighter == maFontWeight) + { + aInherited = getLighter(aInherited); + } + + return aInherited; + } + + // default is FontWeight_400 (FontWeight_normal) + return FontWeight_400; + } + + TextAlign SvgStyleAttributes::getTextAlign() const + { + if(maTextAlign != TextAlign_notset) + { + return maTextAlign; + } + + const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle(); + + if(pSvgStyleAttributes) + { + return pSvgStyleAttributes->getTextAlign(); + } + + // default is TextAlign_left + return TextAlign_left; + } + + const SvgStyleAttributes* SvgStyleAttributes::getTextDecorationDefiningSvgStyleAttributes() const + { + if(maTextDecoration != TextDecoration_notset) + { + return this; + } + + const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle(); + + if(pSvgStyleAttributes) + { + return pSvgStyleAttributes->getTextDecorationDefiningSvgStyleAttributes(); + } + + // default is 0 + return 0; + } + + TextDecoration SvgStyleAttributes::getTextDecoration() const + { + const SvgStyleAttributes* pDefining = getTextDecorationDefiningSvgStyleAttributes(); + + if(pDefining) + { + return pDefining->maTextDecoration; + } + else + { + // default is TextDecoration_none + return TextDecoration_none; + } + } + + TextAnchor SvgStyleAttributes::getTextAnchor() const + { + if(maTextAnchor != TextAnchor_notset) + { + return maTextAnchor; + } + + const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle(); + + if(pSvgStyleAttributes) + { + return pSvgStyleAttributes->getTextAnchor(); + } + + // default is TextAnchor_start + return TextAnchor_start; + } + + const basegfx::BColor* SvgStyleAttributes::getColor() const + { + if(maColor.isSet()) + { + if(maColor.isCurrent()) + { + OSL_ENSURE(false, "Svg error: current color uses current color (!)"); + return 0; + } + else if(maColor.isOn()) + { + return &maColor.getBColor(); + } + } + else + { + const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle(); + + if(pSvgStyleAttributes) + { + return pSvgStyleAttributes->getColor(); + } + } + + return 0; + } + + const rtl::OUString SvgStyleAttributes::getMarkerStartXLink() const + { + if(maMarkerStartXLink.getLength()) + { + return maMarkerStartXLink; + } + + const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle(); + + if(pSvgStyleAttributes) + { + return pSvgStyleAttributes->getMarkerStartXLink(); + } + + return rtl::OUString(); + } + + const SvgMarkerNode* SvgStyleAttributes::accessMarkerStartXLink() const + { + if(!mpMarkerStartXLink) + { + const rtl::OUString aMarker(getMarkerStartXLink()); + + if(aMarker.getLength()) + { + const_cast< SvgStyleAttributes* >(this)->mpMarkerStartXLink = dynamic_cast< const SvgMarkerNode* >(mrOwner.getDocument().findSvgNodeById(getMarkerStartXLink())); + } + } + + return mpMarkerStartXLink; + } + + const rtl::OUString SvgStyleAttributes::getMarkerMidXLink() const + { + if(maMarkerMidXLink.getLength()) + { + return maMarkerMidXLink; + } + + const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle(); + + if(pSvgStyleAttributes) + { + return pSvgStyleAttributes->getMarkerMidXLink(); + } + + return rtl::OUString(); + } + + const SvgMarkerNode* SvgStyleAttributes::accessMarkerMidXLink() const + { + if(!mpMarkerMidXLink) + { + const rtl::OUString aMarker(getMarkerMidXLink()); + + if(aMarker.getLength()) + { + const_cast< SvgStyleAttributes* >(this)->mpMarkerMidXLink = dynamic_cast< const SvgMarkerNode* >(mrOwner.getDocument().findSvgNodeById(getMarkerMidXLink())); + } + } + + return mpMarkerMidXLink; + } + + const rtl::OUString SvgStyleAttributes::getMarkerEndXLink() const + { + if(maMarkerEndXLink.getLength()) + { + return maMarkerEndXLink; + } + + const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle(); + + if(pSvgStyleAttributes) + { + return pSvgStyleAttributes->getMarkerEndXLink(); + } + + return rtl::OUString(); + } + + const SvgMarkerNode* SvgStyleAttributes::accessMarkerEndXLink() const + { + if(!mpMarkerEndXLink) + { + const rtl::OUString aMarker(getMarkerEndXLink()); + + if(aMarker.getLength()) + { + const_cast< SvgStyleAttributes* >(this)->mpMarkerEndXLink = dynamic_cast< const SvgMarkerNode* >(mrOwner.getDocument().findSvgNodeById(getMarkerEndXLink())); + } + } + + return mpMarkerEndXLink; + } + + } // end of namespace svgreader +} // end of namespace svgio + +////////////////////////////////////////////////////////////////////////////// +// eof + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svgio/source/svgreader/svgstylenode.cxx b/svgio/source/svgreader/svgstylenode.cxx new file mode 100644 index 000000000000..9060ac0b9a7d --- /dev/null +++ b/svgio/source/svgreader/svgstylenode.cxx @@ -0,0 +1,127 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <svgio/svgreader/svgstylenode.hxx> +#include <svgio/svgreader/svgdocument.hxx> + +////////////////////////////////////////////////////////////////////////////// + +namespace svgio +{ + namespace svgreader + { + SvgStyleNode::SvgStyleNode( + SvgDocument& rDocument, + SvgNode* pParent) + : SvgNode(SVGTokenStyle, rDocument, pParent), + maSvgStyleAttributes(), + mbTextCss(false) + { + } + + SvgStyleNode::~SvgStyleNode() + { + while(!maSvgStyleAttributes.empty()) + { + delete *(maSvgStyleAttributes.end() - 1); + maSvgStyleAttributes.pop_back(); + } + } + + void SvgStyleNode::parseAttribute(const rtl::OUString& rTokenName, SVGToken aSVGToken, const rtl::OUString& aContent) + { + // call parent + SvgNode::parseAttribute(rTokenName, aSVGToken, aContent); + + // parse own + switch(aSVGToken) + { + case SVGTokenType: + { + if(aContent.getLength()) + { + static rtl::OUString aStrTextCss(rtl::OUString::createFromAscii("text/css")); + + if(aContent.match(aStrTextCss)) + { + setTextCss(true); + } + } + break; + } + default: + { + break; + } + } + } + + void SvgStyleNode::addCssStyleSheet(const rtl::OUString& aContent) + { + const sal_Int32 nLen(aContent.getLength()); + + if(nLen) + { + sal_Int32 nPos(0); + rtl::OUStringBuffer aTokenValue; + + while(nPos < nLen) + { + const sal_Int32 nInitPos(nPos); + skip_char(aContent, sal_Unicode(' '), sal_Unicode('#'), nPos, nLen); + copyToLimiter(aContent, sal_Unicode('{'), nPos, aTokenValue, nLen); + const rtl::OUString aStyleName = aTokenValue.makeStringAndClear().trim(); + + if(aStyleName.getLength() && nPos < nLen) + { + skip_char(aContent, sal_Unicode(' '), sal_Unicode('{'), nPos, nLen); + copyToLimiter(aContent, sal_Unicode('}'), nPos, aTokenValue, nLen); + skip_char(aContent, sal_Unicode(' '), sal_Unicode('}'), nPos, nLen); + const rtl::OUString aStyleContent = aTokenValue.makeStringAndClear().trim(); + + if(aStyleContent.getLength()) + { + // create new style + SvgStyleAttributes* pNewStyle = new SvgStyleAttributes(*this); + maSvgStyleAttributes.push_back(pNewStyle); + + // fill with content + pNewStyle->readStyle(aStyleContent); + + // register new style at document + const_cast< SvgDocument& >(getDocument()).addSvgStyleAttributesToMapper(aStyleName, *pNewStyle); + } + } + + if(nInitPos == nPos) + { + OSL_ENSURE(false, "Could not interpret on current position (!)"); + nPos++; + } + } + } + } + + } // end of namespace svgreader +} // end of namespace svgio + +////////////////////////////////////////////////////////////////////////////// +// eof + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svgio/source/svgreader/svgsvgnode.cxx b/svgio/source/svgreader/svgsvgnode.cxx new file mode 100644 index 000000000000..ecf74d9bb4a6 --- /dev/null +++ b/svgio/source/svgreader/svgsvgnode.cxx @@ -0,0 +1,423 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <svgio/svgreader/svgsvgnode.hxx> +#include <drawinglayer/geometry/viewinformation2d.hxx> +#include <drawinglayer/primitive2d/transformprimitive2d.hxx> +#include <drawinglayer/primitive2d/maskprimitive2d.hxx> +#include <basegfx/polygon/b2dpolygontools.hxx> +#include <basegfx/polygon/b2dpolygon.hxx> +#include <basegfx/matrix/b2dhommatrixtools.hxx> +#include <drawinglayer/primitive2d/polygonprimitive2d.hxx> +#include <drawinglayer/primitive2d/hiddengeometryprimitive2d.hxx> + +////////////////////////////////////////////////////////////////////////////// + +namespace svgio +{ + namespace svgreader + { + SvgSvgNode::SvgSvgNode( + SvgDocument& rDocument, + SvgNode* pParent) + : SvgNode(SVGTokenSvg, rDocument, pParent), + maSvgStyleAttributes(*this), + mpViewBox(0), + maSvgAspectRatio(), + maX(), + maY(), + maWidth(), + maHeight(), + maVersion() + { + if(!getParent()) + { + // initial fill is black + maSvgStyleAttributes.setFill(SvgPaint(basegfx::BColor(0.0, 0.0, 0.0), true, true)); + } + } + + SvgSvgNode::~SvgSvgNode() + { + if(mpViewBox) delete mpViewBox; + } + + const SvgStyleAttributes* SvgSvgNode::getSvgStyleAttributes() const + { + return &maSvgStyleAttributes; + } + + void SvgSvgNode::parseAttribute(const rtl::OUString& rTokenName, SVGToken aSVGToken, const rtl::OUString& aContent) + { + // call parent + SvgNode::parseAttribute(rTokenName, aSVGToken, aContent); + + // read style attributes + maSvgStyleAttributes.parseStyleAttribute(rTokenName, aSVGToken, aContent); + + // parse own + switch(aSVGToken) + { + case SVGTokenStyle: + { + maSvgStyleAttributes.readStyle(aContent); + break; + } + case SVGTokenViewBox: + { + const basegfx::B2DRange aRange(readViewBox(aContent, *this)); + + if(!aRange.isEmpty()) + { + setViewBox(&aRange); + } + break; + } + case SVGTokenPreserveAspectRatio: + { + setSvgAspectRatio(readSvgAspectRatio(aContent)); + break; + } + case SVGTokenX: + { + SvgNumber aNum; + + if(readSingleNumber(aContent, aNum)) + { + setX(aNum); + } + break; + } + case SVGTokenY: + { + SvgNumber aNum; + + if(readSingleNumber(aContent, aNum)) + { + setY(aNum); + } + break; + } + case SVGTokenWidth: + { + SvgNumber aNum; + + if(readSingleNumber(aContent, aNum)) + { + if(aNum.isPositive()) + { + setWidth(aNum); + } + } + break; + } + case SVGTokenHeight: + { + SvgNumber aNum; + + if(readSingleNumber(aContent, aNum)) + { + if(aNum.isPositive()) + { + setHeight(aNum); + } + } + break; + } + case SVGTokenVersion: + { + SvgNumber aNum; + + if(readSingleNumber(aContent, aNum)) + { + setVersion(aNum); + } + break; + } + default: + { + break; + } + } + } + + void SvgSvgNode::decomposeSvgNode(drawinglayer::primitive2d::Primitive2DSequence& rTarget, bool bReferenced) const + { + drawinglayer::primitive2d::Primitive2DSequence aSequence; + + // decompose childs + SvgNode::decomposeSvgNode(aSequence, bReferenced); + + if(aSequence.hasElements()) + { + if(getParent()) + { + if(getViewBox()) + { + // Svg defines that with no width or no height the viewBox content is empty, + // so both need to exist + if(!basegfx::fTools::equalZero(getViewBox()->getWidth()) && !basegfx::fTools::equalZero(getViewBox()->getHeight())) + { + // create target range homing x,y, width and height as given + const double fX(getX().isSet() ? getX().solve(*this, xcoordinate) : 0.0); + const double fY(getY().isSet() ? getY().solve(*this, ycoordinate) : 0.0); + const double fW(getWidth().isSet() ? getWidth().solve(*this, xcoordinate) : getViewBox()->getWidth()); + const double fH(getHeight().isSet() ? getHeight().solve(*this, ycoordinate) : getViewBox()->getHeight()); + const basegfx::B2DRange aTarget(fX, fY, fX + fW, fY + fH); + + if(aTarget.equal(*getViewBox())) + { + // no mapping needed, append + drawinglayer::primitive2d::appendPrimitive2DSequenceToPrimitive2DSequence(rTarget, aSequence); + } + else + { + // create mapping + const SvgAspectRatio& rRatio = getSvgAspectRatio(); + + if(rRatio.isSet()) + { + // let mapping be created from SvgAspectRatio + const basegfx::B2DHomMatrix aEmbeddingTransform( + rRatio.createMapping(aTarget, *getViewBox())); + + // prepare embedding in transformation + const drawinglayer::primitive2d::Primitive2DReference xRef( + new drawinglayer::primitive2d::TransformPrimitive2D( + aEmbeddingTransform, + aSequence)); + + if(rRatio.isMeetOrSlice()) + { + // embed in transformation + drawinglayer::primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(rTarget, xRef); + } + else + { + // need to embed in MaskPrimitive2D, too + const drawinglayer::primitive2d::Primitive2DReference xMask( + new drawinglayer::primitive2d::MaskPrimitive2D( + basegfx::B2DPolyPolygon(basegfx::tools::createPolygonFromRect(aTarget)), + drawinglayer::primitive2d::Primitive2DSequence(&xRef, 1))); + + drawinglayer::primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(rTarget, xMask); + } + } + else + { + // choose default mapping + const basegfx::B2DHomMatrix aEmbeddingTransform( + rRatio.createLinearMapping( + aTarget, *getViewBox())); + + // embed in transformation + const drawinglayer::primitive2d::Primitive2DReference xTransform( + new drawinglayer::primitive2d::TransformPrimitive2D( + aEmbeddingTransform, + aSequence)); + + drawinglayer::primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(rTarget, xTransform); + } + } + } + } + else + { + // check if we have a size + const double fW(getWidth().isSet() ? getWidth().solve(*this, xcoordinate) : 0.0); + const double fH(getHeight().isSet() ? getHeight().solve(*this, ycoordinate) : 0.0); + + // Svg defines that a negative value is an error and that 0.0 disables rendering + if(basegfx::fTools::more(fW, 0.0) && basegfx::fTools::more(fH, 0.0)) + { + // check if we have a x,y position + const double fX(getX().isSet() ? getX().solve(*this, xcoordinate) : 0.0); + const double fY(getY().isSet() ? getY().solve(*this, ycoordinate) : 0.0); + + if(!basegfx::fTools::equalZero(fX) || !basegfx::fTools::equalZero(fY)) + { + // embed in transform + const drawinglayer::primitive2d::Primitive2DReference xRef( + new drawinglayer::primitive2d::TransformPrimitive2D( + basegfx::tools::createTranslateB2DHomMatrix(fX, fY), + aSequence)); + + aSequence = drawinglayer::primitive2d::Primitive2DSequence(&xRef, 1); + } + + // embed in MaskPrimitive2D to clip + const drawinglayer::primitive2d::Primitive2DReference xMask( + new drawinglayer::primitive2d::MaskPrimitive2D( + basegfx::B2DPolyPolygon( + basegfx::tools::createPolygonFromRect( + basegfx::B2DRange(fX, fY, fX + fW, fY + fH))), + aSequence)); + + // append + drawinglayer::primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(rTarget, xMask); + } + } + } + else + { + // Outermost SVG element; create target range homing width and height as given. + // SVG defines that x,y has no meanig for the outermost SVG element. Use a fallback + // width and height of din A 4 (21 x 29,7 cm) + double fW(getWidth().isSet() ? getWidth().solve(*this, xcoordinate) : (210.0 * 3.543307)); + double fH(getHeight().isSet() ? getHeight().solve(*this, ycoordinate) : (297.0 * 3.543307)); + + // Svg defines that a negative value is an error and that 0.0 disables rendering + if(basegfx::fTools::more(fW, 0.0) && basegfx::fTools::more(fH, 0.0)) + { + const basegfx::B2DRange aSvgCanvasRange(0.0, 0.0, fW, fH); + + if(getViewBox()) + { + if(!basegfx::fTools::equalZero(getViewBox()->getWidth()) && !basegfx::fTools::equalZero(getViewBox()->getHeight())) + { + // create mapping + const SvgAspectRatio& rRatio = getSvgAspectRatio(); + basegfx::B2DHomMatrix aViewBoxMapping; + + if(rRatio.isSet()) + { + // let mapping be created from SvgAspectRatio + aViewBoxMapping = rRatio.createMapping(aSvgCanvasRange, *getViewBox()); + + // no need to check ratio here for slice, the outermost Svg will + // be clipped anyways (see below) + } + else + { + // choose default mapping + aViewBoxMapping = rRatio.createLinearMapping(aSvgCanvasRange, *getViewBox()); + } + + // scale content to viewBox definitions + const drawinglayer::primitive2d::Primitive2DReference xTransform( + new drawinglayer::primitive2d::TransformPrimitive2D( + aViewBoxMapping, + aSequence)); + + aSequence = drawinglayer::primitive2d::Primitive2DSequence(&xTransform, 1); + } + } + + // to be completely correct in Svg sense it is necessary to clip + // the whole content to the given canvas. I choose here to do this + // initially despite I found various examples of Svg files out there + // which have no correct values for this clipping. It's correct + // due to the Svg spec. + bool bDoCorrectCanvasClipping(true); + + if(bDoCorrectCanvasClipping) + { + // different from Svg we have the possibility with primitives to get + // a correct bounding box for the geometry. Get it for evtl. taking action + const basegfx::B2DRange aContentRange( + drawinglayer::primitive2d::getB2DRangeFromPrimitive2DSequence( + aSequence, + drawinglayer::geometry::ViewInformation2D())); + + if(aSvgCanvasRange.isInside(aContentRange)) + { + // no clip needed, but an invisible HiddenGeometryPrimitive2D + // to allow getting the full Svg range using the primitive mechanisms. + // This is needed since e.g. an SdrObject using this as graphic will + // create a mapping transformation to exactly map the content to it's + // real life size + const drawinglayer::primitive2d::Primitive2DReference xLine( + new drawinglayer::primitive2d::PolygonHairlinePrimitive2D( + basegfx::tools::createPolygonFromRect( + aSvgCanvasRange), + basegfx::BColor(0.0, 0.0, 0.0))); + const drawinglayer::primitive2d::Primitive2DReference xHidden( + new drawinglayer::primitive2d::HiddenGeometryPrimitive2D( + drawinglayer::primitive2d::Primitive2DSequence(&xLine, 1))); + + drawinglayer::primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(aSequence, xHidden); + } + else if(aSvgCanvasRange.overlaps(aContentRange)) + { + // Clip is necessary. This will make Svg images evtl. smaller + // than wanted from Svg (the free space which may be around it is + // conform to the Svg spec), but avoids an expensive and unneccessary + // clip. Keep the full Svg range here to get the correct mappings + // to objects using this. Optimizations can be done in the processors + const drawinglayer::primitive2d::Primitive2DReference xMask( + new drawinglayer::primitive2d::MaskPrimitive2D( + basegfx::B2DPolyPolygon( + basegfx::tools::createPolygonFromRect( + aSvgCanvasRange)), + aSequence)); + + aSequence = drawinglayer::primitive2d::Primitive2DSequence(&xMask, 1); + } + else + { + // not inside, no overlap. Empty Svg + aSequence.realloc(0); + } + } + + if(aSequence.hasElements()) + { + // embed in transform primitive to scale to 1/100th mm + // where 1 mm == 3.543307 px to get from Svg coordinates to + // drawinglayer ones + const double fScaleTo100thmm(100.0 / 3.543307); + const basegfx::B2DHomMatrix aTransform( + basegfx::tools::createScaleB2DHomMatrix( + fScaleTo100thmm, + fScaleTo100thmm)); + + const drawinglayer::primitive2d::Primitive2DReference xTransform( + new drawinglayer::primitive2d::TransformPrimitive2D( + aTransform, + aSequence)); + + aSequence = drawinglayer::primitive2d::Primitive2DSequence(&xTransform, 1); + + // append to result + drawinglayer::primitive2d::appendPrimitive2DSequenceToPrimitive2DSequence(rTarget, aSequence); + } + } + } + } + } + + const basegfx::B2DRange* SvgSvgNode::getCurrentViewPort() const + { + if(getViewBox()) + { + return getViewBox(); + } + else + { + return SvgNode::getCurrentViewPort(); + } + } + + } // end of namespace svgreader +} // end of namespace svgio + +////////////////////////////////////////////////////////////////////////////// +// eof + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svgio/source/svgreader/svgsymbolnode.cxx b/svgio/source/svgreader/svgsymbolnode.cxx new file mode 100644 index 000000000000..2c8ec2ef8149 --- /dev/null +++ b/svgio/source/svgreader/svgsymbolnode.cxx @@ -0,0 +1,94 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <svgio/svgreader/svgsymbolnode.hxx> +#include <drawinglayer/geometry/viewinformation2d.hxx> +#include <drawinglayer/primitive2d/transformprimitive2d.hxx> + +////////////////////////////////////////////////////////////////////////////// + +namespace svgio +{ + namespace svgreader + { + SvgSymbolNode::SvgSymbolNode( + SvgDocument& rDocument, + SvgNode* pParent) + : SvgNode(SVGTokenSvg, rDocument, pParent), + maSvgStyleAttributes(*this), + mpViewBox(0), + maSvgAspectRatio() + { + } + + SvgSymbolNode::~SvgSymbolNode() + { + if(mpViewBox) delete mpViewBox; + } + + const SvgStyleAttributes* SvgSymbolNode::getSvgStyleAttributes() const + { + return &maSvgStyleAttributes; + } + + void SvgSymbolNode::parseAttribute(const rtl::OUString& rTokenName, SVGToken aSVGToken, const rtl::OUString& aContent) + { + // call parent + SvgNode::parseAttribute(rTokenName, aSVGToken, aContent); + + // read style attributes + maSvgStyleAttributes.parseStyleAttribute(rTokenName, aSVGToken, aContent); + + // parse own + switch(aSVGToken) + { + case SVGTokenStyle: + { + maSvgStyleAttributes.readStyle(aContent); + break; + } + case SVGTokenViewBox: + { + const basegfx::B2DRange aRange(readViewBox(aContent, *this)); + + if(!aRange.isEmpty()) + { + setViewBox(&aRange); + } + break; + } + case SVGTokenPreserveAspectRatio: + { + setSvgAspectRatio(readSvgAspectRatio(aContent)); + break; + } + default: + { + break; + } + } + } + + } // end of namespace svgreader +} // end of namespace svgio + +////////////////////////////////////////////////////////////////////////////// +// eof + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svgio/source/svgreader/svgtextnode.cxx b/svgio/source/svgreader/svgtextnode.cxx new file mode 100644 index 000000000000..8340abd31d98 --- /dev/null +++ b/svgio/source/svgreader/svgtextnode.cxx @@ -0,0 +1,274 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <svgio/svgreader/svgtextnode.hxx> +#include <svgio/svgreader/svgcharacternode.hxx> +#include <svgio/svgreader/svgstyleattributes.hxx> +#include <svgio/svgreader/svgtrefnode.hxx> +#include <svgio/svgreader/svgtextpathnode.hxx> +#include <svgio/svgreader/svgtspannode.hxx> +#include <drawinglayer/primitive2d/transformprimitive2d.hxx> +#include <drawinglayer/primitive2d/unifiedtransparenceprimitive2d.hxx> + +////////////////////////////////////////////////////////////////////////////// + +namespace svgio +{ + namespace svgreader + { + SvgTextNode::SvgTextNode( + SvgDocument& rDocument, + SvgNode* pParent) + : SvgNode(SVGTokenText, rDocument, pParent), + maSvgStyleAttributes(*this), + mpaTransform(0), + maSvgTextPositions() + { + } + + SvgTextNode::~SvgTextNode() + { + if(mpaTransform) delete mpaTransform; + } + + const SvgStyleAttributes* SvgTextNode::getSvgStyleAttributes() const + { + static rtl::OUString aClassStr(rtl::OUString::createFromAscii("text")); + maSvgStyleAttributes.checkForCssStyle(aClassStr); + + return &maSvgStyleAttributes; + } + + void SvgTextNode::parseAttribute(const rtl::OUString& rTokenName, SVGToken aSVGToken, const rtl::OUString& aContent) + { + // call parent + SvgNode::parseAttribute(rTokenName, aSVGToken, aContent); + + // read style attributes + maSvgStyleAttributes.parseStyleAttribute(rTokenName, aSVGToken, aContent); + + // read text position attributes + maSvgTextPositions.parseTextPositionAttributes(rTokenName, aSVGToken, aContent); + + // parse own + switch(aSVGToken) + { + case SVGTokenStyle: + { + maSvgStyleAttributes.readStyle(aContent); + break; + } + case SVGTokenTransform: + { + const basegfx::B2DHomMatrix aMatrix(readTransform(aContent, *this)); + + if(!aMatrix.isIdentity()) + { + setTransform(&aMatrix); + } + break; + } + default: + { + break; + } + } + } + + void SvgTextNode::addTextPrimitives( + const SvgNode& rCandidate, + drawinglayer::primitive2d::Primitive2DSequence& rTarget, + drawinglayer::primitive2d::Primitive2DSequence& rSource) const + { + if(rSource.hasElements()) + { + const SvgStyleAttributes* pAttributes = rCandidate.getSvgStyleAttributes(); + + if(pAttributes) + { + // add text with taking all Fill/Stroke attributes into account + pAttributes->add_text(rTarget, rSource); + } + else + { + // should not happen, every subnode from SvgTextNode will at least + // return the attributes from SvgTextNode. Nonetheless, add text + drawinglayer::primitive2d::appendPrimitive2DSequenceToPrimitive2DSequence(rTarget, rSource); + } + } + } + + void SvgTextNode::DecomposeChild(const SvgNode& rCandidate, drawinglayer::primitive2d::Primitive2DSequence& rTarget, SvgTextPosition& rSvgTextPosition) const + { + switch(rCandidate.getType()) + { + case SVGTokenCharacter: + { + // direct SvgTextPathNode derivates, decompose them + const SvgCharacterNode& rSvgCharacterNode = static_cast< const SvgCharacterNode& >(rCandidate); + rSvgCharacterNode.decomposeText(rTarget, rSvgTextPosition); + break; + } + case SVGTokenTextPath: + { + // direct TextPath decompose + const SvgTextPathNode& rSvgTextPathNode = static_cast< const SvgTextPathNode& >(rCandidate); + const SvgNodeVector& rChildren = rSvgTextPathNode.getChildren(); + const sal_uInt32 nCount(rChildren.size()); + + if(nCount && rSvgTextPathNode.isValid()) + { + // remember original TextStart to later detect hor/ver offsets + const basegfx::B2DPoint aTextStart(rSvgTextPosition.getPosition()); + drawinglayer::primitive2d::Primitive2DSequence aNewTarget; + + // decompose to regular TextPrimitives + for(sal_uInt32 a(0); a < nCount; a++) + { + DecomposeChild(*rChildren[a], aNewTarget, rSvgTextPosition); + } + + if(aNewTarget.hasElements()) + { + const drawinglayer::primitive2d::Primitive2DSequence aPathContent(aNewTarget); + aNewTarget.realloc(0); + + // dismantle TextPrimitives and map them on curve/path + rSvgTextPathNode.decomposePathNode(aPathContent, aNewTarget, aTextStart); + } + + if(aNewTarget.hasElements()) + { + addTextPrimitives(rCandidate, rTarget, aNewTarget); + } + } + + break; + } + case SVGTokenTspan: + { + // Tspan may have children, call recursively + const SvgTspanNode& rSvgTspanNode = static_cast< const SvgTspanNode& >(rCandidate); + const SvgNodeVector& rChildren = rSvgTspanNode.getChildren(); + const sal_uInt32 nCount(rChildren.size()); + + if(nCount) + { + SvgTextPosition aSvgTextPosition(&rSvgTextPosition, rSvgTspanNode, rSvgTspanNode.getSvgTextPositions()); + drawinglayer::primitive2d::Primitive2DSequence aNewTarget; + + for(sal_uInt32 a(0); a < nCount; a++) + { + DecomposeChild(*rChildren[a], aNewTarget, aSvgTextPosition); + } + + rSvgTextPosition.setPosition(aSvgTextPosition.getPosition()); + + if(aNewTarget.hasElements()) + { + addTextPrimitives(rCandidate, rTarget, aNewTarget); + } + } + break; + } + case SVGTokenTref: + { + const SvgTrefNode& rSvgTrefNode = static_cast< const SvgTrefNode& >(rCandidate); + const SvgTextNode* pRefText = rSvgTrefNode.getReferencedSvgTextNode(); + + if(pRefText) + { + const SvgNodeVector& rChildren = pRefText->getChildren(); + const sal_uInt32 nCount(rChildren.size()); + drawinglayer::primitive2d::Primitive2DSequence aNewTarget; + + if(nCount) + { + for(sal_uInt32 a(0); a < nCount; a++) + { + const SvgNode& rChildCandidate = *rChildren[a]; + const_cast< SvgNode& >(rChildCandidate).setAlternativeParent(this); + + DecomposeChild(rChildCandidate, aNewTarget, rSvgTextPosition); + const_cast< SvgNode& >(rChildCandidate).setAlternativeParent(0); + } + + if(aNewTarget.hasElements()) + { + addTextPrimitives(rCandidate, rTarget, aNewTarget); + } + } + } + + break; + } + default: + { + OSL_ENSURE(false, "Unexpected node in text token (!)"); + break; + } + } + } + + void SvgTextNode::decomposeSvgNode(drawinglayer::primitive2d::Primitive2DSequence& rTarget, bool /*bReferenced`*/) const + { + // text has a group of child nodes, allowed are SVGTokenCharacter, SVGTokenTspan, + // SVGTokenTref and SVGTokenTextPath. These increase a given current text position + const SvgStyleAttributes* pStyle = getSvgStyleAttributes(); + + if(pStyle && !getChildren().empty()) + { + const double fOpacity(pStyle->getOpacity().getNumber()); + + if(fOpacity > 0.0) + { + SvgTextPosition aSvgTextPosition(0, *this, getSvgTextPositions()); + drawinglayer::primitive2d::Primitive2DSequence aNewTarget; + const SvgNodeVector& rChildren = getChildren(); + const sal_uInt32 nCount(rChildren.size()); + + for(sal_uInt32 a(0); a < nCount; a++) + { + const SvgNode& rCandidate = *rChildren[a]; + + DecomposeChild(rCandidate, aNewTarget, aSvgTextPosition); + } + + if(aNewTarget.hasElements()) + { + drawinglayer::primitive2d::Primitive2DSequence aNewTarget2; + + addTextPrimitives(*this, aNewTarget2, aNewTarget); + aNewTarget = aNewTarget2; + } + + if(aNewTarget.hasElements()) + { + pStyle->add_postProcess(rTarget, aNewTarget, getTransform()); + } + } + } + } + } // end of namespace svgreader +} // end of namespace svgio + +////////////////////////////////////////////////////////////////////////////// +// eof + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svgio/source/svgreader/svgtextpathnode.cxx b/svgio/source/svgreader/svgtextpathnode.cxx new file mode 100644 index 000000000000..ba7de86612ae --- /dev/null +++ b/svgio/source/svgreader/svgtextpathnode.cxx @@ -0,0 +1,511 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <svgio/svgreader/svgtextpathnode.hxx> +#include <svgio/svgreader/svgstyleattributes.hxx> +#include <svgio/svgreader/svgpathnode.hxx> +#include <svgio/svgreader/svgdocument.hxx> +#include <svgio/svgreader/svgtrefnode.hxx> +#include <basegfx/polygon/b2dpolygon.hxx> +#include <basegfx/polygon/b2dpolygontools.hxx> +#include <drawinglayer/primitive2d/textbreakuphelper.hxx> +#include <drawinglayer/primitive2d/groupprimitive2d.hxx> +#include <basegfx/curve/b2dcubicbezier.hxx> +#include <basegfx/curve/b2dbeziertools.hxx> + +////////////////////////////////////////////////////////////////////////////// + +namespace svgio +{ + namespace svgreader + { + class pathTextBreakupHelper : public drawinglayer::primitive2d::TextBreakupHelper + { + private: + const basegfx::B2DPolygon& mrPolygon; + const double mfBasegfxPathLength; + const double mfUserToBasegfx; + double mfPosition; + const basegfx::B2DPoint& mrTextStart; + + const sal_uInt32 mnMaxIndex; + sal_uInt32 mnIndex; + basegfx::B2DCubicBezier maCurrentSegment; + basegfx::B2DCubicBezierHelper* mpB2DCubicBezierHelper; + double mfCurrentSegmentLength; + double mfSegmentStartPosition; + + protected: + /// allow user callback to allow changes to the new TextTransformation. Default + /// does nothing. + virtual bool allowChange(sal_uInt32 nCount, basegfx::B2DHomMatrix& rNewTransform, sal_uInt32 nIndex, sal_uInt32 nLength); + + void freeB2DCubicBezierHelper(); + basegfx::B2DCubicBezierHelper* getB2DCubicBezierHelper(); + void advanceToPosition(double fNewPosition); + + public: + pathTextBreakupHelper( + const drawinglayer::primitive2d::TextSimplePortionPrimitive2D& rSource, + const basegfx::B2DPolygon& rPolygon, + const double fBasegfxPathLength, + const double fUserToBasegfx, + double fPosition, + const basegfx::B2DPoint& rTextStart); + virtual ~pathTextBreakupHelper(); + + // read access to evtl. advanced position + double getPosition() const { return mfPosition; } + + // get length of given text + double getLength(const rtl::OUString& rText) const; + }; + + double pathTextBreakupHelper::getLength(const rtl::OUString& rText) const + { + const sal_uInt32 nLength(rText.getLength()); + + if(nLength) + { + return getTextLayouter().getTextWidth(rText, 0, nLength); + } + + return 0.0; + } + + void pathTextBreakupHelper::freeB2DCubicBezierHelper() + { + if(mpB2DCubicBezierHelper) + { + delete mpB2DCubicBezierHelper; + mpB2DCubicBezierHelper = 0; + } + } + + basegfx::B2DCubicBezierHelper* pathTextBreakupHelper::getB2DCubicBezierHelper() + { + if(!mpB2DCubicBezierHelper && maCurrentSegment.isBezier()) + { + mpB2DCubicBezierHelper = new basegfx::B2DCubicBezierHelper(maCurrentSegment); + } + + return mpB2DCubicBezierHelper; + } + + void pathTextBreakupHelper::advanceToPosition(double fNewPosition) + { + while(mfSegmentStartPosition + mfCurrentSegmentLength < fNewPosition && mnIndex < mnMaxIndex) + { + mfSegmentStartPosition += mfCurrentSegmentLength; + mnIndex++; + + if(mnIndex < mnMaxIndex) + { + freeB2DCubicBezierHelper(); + mrPolygon.getBezierSegment(mnIndex % mrPolygon.count(), maCurrentSegment); + maCurrentSegment.testAndSolveTrivialBezier(); + mfCurrentSegmentLength = getB2DCubicBezierHelper() + ? getB2DCubicBezierHelper()->getLength() + : maCurrentSegment.getLength(); + } + } + + mfPosition = fNewPosition; + } + + pathTextBreakupHelper::pathTextBreakupHelper( + const drawinglayer::primitive2d::TextSimplePortionPrimitive2D& rSource, + const basegfx::B2DPolygon& rPolygon, + const double fBasegfxPathLength, + const double fUserToBasegfx, + double fPosition, + const basegfx::B2DPoint& rTextStart) + : drawinglayer::primitive2d::TextBreakupHelper(rSource), + mrPolygon(rPolygon), + mfBasegfxPathLength(fBasegfxPathLength), + mfUserToBasegfx(fUserToBasegfx), + mfPosition(0.0), + mrTextStart(rTextStart), + mnMaxIndex(rPolygon.isClosed() ? rPolygon.count() : rPolygon.count() - 1), + mnIndex(0), + maCurrentSegment(), + mpB2DCubicBezierHelper(0), + mfCurrentSegmentLength(0.0), + mfSegmentStartPosition(0.0) + { + mrPolygon.getBezierSegment(mnIndex % mrPolygon.count(), maCurrentSegment); + mfCurrentSegmentLength = maCurrentSegment.getLength(); + + advanceToPosition(fPosition); + } + + pathTextBreakupHelper::~pathTextBreakupHelper() + { + freeB2DCubicBezierHelper(); + } + + bool pathTextBreakupHelper::allowChange(sal_uInt32 /*nCount*/, basegfx::B2DHomMatrix& rNewTransform, sal_uInt32 nIndex, sal_uInt32 nLength) + { + bool bRetval(false); + + if(mfPosition < mfBasegfxPathLength && nLength && mnIndex < mnMaxIndex) + { + const double fSnippetWidth( + getTextLayouter().getTextWidth( + getSource().getText(), + nIndex, + nLength)); + + if(basegfx::fTools::more(fSnippetWidth, 0.0)) + { + const ::rtl::OUString aText(getSource().getText()); + const ::rtl::OUString aTrimmedChars(aText.copy(nIndex, nLength).trim()); + const double fEndPos(mfPosition + fSnippetWidth); + + if(aTrimmedChars.getLength() && (mfPosition < mfBasegfxPathLength || fEndPos > 0.0)) + { + const double fHalfSnippetWidth(fSnippetWidth * 0.5); + + advanceToPosition(mfPosition + fHalfSnippetWidth); + + // create representation for this snippet + bRetval = true; + + // get target position and tangent in that pint + basegfx::B2DPoint aPosition(0.0, 0.0); + basegfx::B2DVector aTangent(0.0, 1.0); + + if(mfPosition < 0.0) + { + // snippet center is left of first segment, but right edge is on it (SVG allows that) + aTangent = maCurrentSegment.getTangent(0.0); + aTangent.normalize(); + aPosition = maCurrentSegment.getStartPoint() + (aTangent * (mfPosition - mfSegmentStartPosition)); + } + else if(mfPosition > mfBasegfxPathLength) + { + // snippet center is right of last segment, but left edge is on it (SVG allows that) + aTangent = maCurrentSegment.getTangent(1.0); + aTangent.normalize(); + aPosition = maCurrentSegment.getEndPoint() + (aTangent * (mfPosition - mfSegmentStartPosition)); + } + else + { + // snippet center inside segment, interpolate + double fBezierDistance(mfPosition - mfSegmentStartPosition); + + if(getB2DCubicBezierHelper()) + { + // use B2DCubicBezierHelper to bridge the non-linear gap between + // length and bezier distances (if it's a bezier segment) + fBezierDistance = getB2DCubicBezierHelper()->distanceToRelative(fBezierDistance); + } + else + { + // linear relationship, make relative to segment length + fBezierDistance = fBezierDistance / mfCurrentSegmentLength; + } + + aPosition = maCurrentSegment.interpolatePoint(fBezierDistance); + aTangent = maCurrentSegment.getTangent(fBezierDistance); + aTangent.normalize(); + } + + // detect evtl. hor/ver translations (depends on text direction) + const basegfx::B2DPoint aBasePoint(rNewTransform * basegfx::B2DPoint(0.0, 0.0)); + const basegfx::B2DVector aOffset(aBasePoint - mrTextStart); + + if(!basegfx::fTools::equalZero(aOffset.getY())) + { + // ...and apply + aPosition.setY(aPosition.getY() + aOffset.getY()); + } + + // move target position from snippet center to left text start + aPosition -= fHalfSnippetWidth * aTangent; + + // remove current translation + rNewTransform.translate(-aBasePoint.getX(), -aBasePoint.getY()); + + // rotate due to tangent + rNewTransform.rotate(atan2(aTangent.getY(), aTangent.getX())); + + // add new translation + rNewTransform.translate(aPosition.getX(), aPosition.getY()); + } + + // advance to end + advanceToPosition(fEndPos); + } + } + + return bRetval; + } + + } // end of namespace svgreader +} // end of namespace svgio + +////////////////////////////////////////////////////////////////////////////// + +namespace svgio +{ + namespace svgreader + { + SvgTextPathNode::SvgTextPathNode( + SvgDocument& rDocument, + SvgNode* pParent) + : SvgNode(SVGTokenTextPath, rDocument, pParent), + maSvgStyleAttributes(*this), + maXLink(), + maStartOffset(), + mbMethod(true), + mbSpacing(false) + { + } + + SvgTextPathNode::~SvgTextPathNode() + { + } + + const SvgStyleAttributes* SvgTextPathNode::getSvgStyleAttributes() const + { + return &maSvgStyleAttributes; + } + + void SvgTextPathNode::parseAttribute(const rtl::OUString& rTokenName, SVGToken aSVGToken, const rtl::OUString& aContent) + { + // call parent + SvgNode::parseAttribute(rTokenName, aSVGToken, aContent); + + // read style attributes + maSvgStyleAttributes.parseStyleAttribute(rTokenName, aSVGToken, aContent); + + // parse own + switch(aSVGToken) + { + case SVGTokenStyle: + { + maSvgStyleAttributes.readStyle(aContent); + break; + } + case SVGTokenStartOffset: + { + SvgNumber aNum; + + if(readSingleNumber(aContent, aNum)) + { + if(aNum.isPositive()) + { + setStartOffset(aNum); + } + } + break; + } + case SVGTokenMethod: + { + if(aContent.getLength()) + { + static rtl::OUString aStrAlign(rtl::OUString::createFromAscii("align")); + static rtl::OUString aStrStretch(rtl::OUString::createFromAscii("stretch")); + + if(aContent.match(aStrAlign)) + { + setMethod(true); + } + else if(aContent.match(aStrStretch)) + { + setMethod(false); + } + } + break; + } + case SVGTokenSpacing: + { + if(aContent.getLength()) + { + static rtl::OUString aStrAuto(rtl::OUString::createFromAscii("auto")); + static rtl::OUString aStrExact(rtl::OUString::createFromAscii("exact")); + + if(aContent.match(aStrAuto)) + { + setSpacing(true); + } + else if(aContent.match(aStrExact)) + { + setSpacing(false); + } + } + break; + } + case SVGTokenXlinkHref: + { + const sal_Int32 nLen(aContent.getLength()); + + if(nLen && sal_Unicode('#') == aContent[0]) + { + maXLink = aContent.copy(1); + } + break; + } + default: + { + break; + } + } + } + + bool SvgTextPathNode::isValid() const + { + const SvgPathNode* pSvgPathNode = dynamic_cast< const SvgPathNode* >(getDocument().findSvgNodeById(maXLink)); + + if(!pSvgPathNode) + { + return false; + } + + const basegfx::B2DPolyPolygon* pPolyPolyPath = pSvgPathNode->getPath(); + + if(!pPolyPolyPath || !pPolyPolyPath->count()) + { + return false; + } + + const basegfx::B2DPolygon aPolygon(pPolyPolyPath->getB2DPolygon(0)); + + if(!aPolygon.count()) + { + return false; + } + + const double fBasegfxPathLength(basegfx::tools::getLength(aPolygon)); + + if(basegfx::fTools::equalZero(fBasegfxPathLength)) + { + return false; + } + + return true; + } + + void SvgTextPathNode::decomposePathNode( + const drawinglayer::primitive2d::Primitive2DSequence& rPathContent, + drawinglayer::primitive2d::Primitive2DSequence& rTarget, + const basegfx::B2DPoint& rTextStart) const + { + if(rPathContent.hasElements()) + { + const SvgPathNode* pSvgPathNode = dynamic_cast< const SvgPathNode* >(getDocument().findSvgNodeById(maXLink)); + + if(pSvgPathNode) + { + const basegfx::B2DPolyPolygon* pPolyPolyPath = pSvgPathNode->getPath(); + + if(pPolyPolyPath && pPolyPolyPath->count()) + { + basegfx::B2DPolygon aPolygon(pPolyPolyPath->getB2DPolygon(0)); + + if(pSvgPathNode->getTransform()) + { + aPolygon.transform(*pSvgPathNode->getTransform()); + } + + const double fBasegfxPathLength(basegfx::tools::getLength(aPolygon)); + + if(!basegfx::fTools::equalZero(fBasegfxPathLength)) + { + double fUserToBasegfx(1.0); // multiply: user->basegfx, divide: basegfx->user + + if(pSvgPathNode->getPathLength().isSet()) + { + const double fUserLength(pSvgPathNode->getPathLength().solve(*this, length)); + + if(fUserLength > 0.0 && !basegfx::fTools::equal(fUserLength, fBasegfxPathLength)) + { + fUserToBasegfx = fUserLength / fBasegfxPathLength; + } + } + + double fPosition(0.0); + + if(getStartOffset().isSet()) + { + if(Unit_percent == getStartOffset().getUnit()) + { + // percent are relative to path length + fPosition = getStartOffset().getNumber() * 0.01 * fBasegfxPathLength; + } + else + { + fPosition = getStartOffset().solve(*this, length) * fUserToBasegfx; + } + } + + if(fPosition >= 0.0) + { + const sal_Int32 nLength(rPathContent.getLength()); + sal_Int32 nCurrent(0); + + while(fPosition < fBasegfxPathLength && nCurrent < nLength) + { + const drawinglayer::primitive2d::TextSimplePortionPrimitive2D* pCandidate = 0; + const drawinglayer::primitive2d::Primitive2DReference xReference(rPathContent[nCurrent]); + + if(xReference.is()) + { + pCandidate = dynamic_cast< const drawinglayer::primitive2d::TextSimplePortionPrimitive2D* >(xReference.get()); + } + + if(pCandidate) + { + const pathTextBreakupHelper aPathTextBreakupHelper( + *pCandidate, + aPolygon, + fBasegfxPathLength, + fUserToBasegfx, + fPosition, + rTextStart); + + const drawinglayer::primitive2d::Primitive2DSequence aResult( + aPathTextBreakupHelper.getResult(drawinglayer::primitive2d::BreakupUnit_character)); + + if(aResult.hasElements()) + { + drawinglayer::primitive2d::appendPrimitive2DSequenceToPrimitive2DSequence(rTarget, aResult); + } + + // advance position to consumed + fPosition = aPathTextBreakupHelper.getPosition(); + } + + nCurrent++; + } + } + } + } + } + } + } + + } // end of namespace svgreader +} // end of namespace svgio + +////////////////////////////////////////////////////////////////////////////// +// eof + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svgio/source/svgreader/svgtoken.cxx b/svgio/source/svgreader/svgtoken.cxx new file mode 100644 index 000000000000..a165e9aa4311 --- /dev/null +++ b/svgio/source/svgreader/svgtoken.cxx @@ -0,0 +1,318 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <svgio/svgreader/svgtoken.hxx> + +////////////////////////////////////////////////////////////////////////////// + +namespace svgio +{ + namespace svgreader + { + static rtl::OUString aSVGStrWidth(rtl::OUString::createFromAscii("width")); + static rtl::OUString aSVGStrHeight(rtl::OUString::createFromAscii("height")); + static rtl::OUString aSVGStrViewBox(rtl::OUString::createFromAscii("viewBox")); + static rtl::OUString aSVGStrTransform(rtl::OUString::createFromAscii("transform")); + static rtl::OUString aSVGStrStyle(rtl::OUString::createFromAscii("style")); + static rtl::OUString aSVGStrD(rtl::OUString::createFromAscii("d")); + static rtl::OUString aSVGStrX(rtl::OUString::createFromAscii("x")); + static rtl::OUString aSVGStrY(rtl::OUString::createFromAscii("y")); + static rtl::OUString aSVGStrXmlns(rtl::OUString::createFromAscii("xmlns")); + static rtl::OUString aSVGStrVersion(rtl::OUString::createFromAscii("version")); + static rtl::OUString aSVGStrId(rtl::OUString::createFromAscii("id")); + static rtl::OUString aSVGStrRx(rtl::OUString::createFromAscii("rx")); + static rtl::OUString aSVGStrRy(rtl::OUString::createFromAscii("ry")); + static rtl::OUString aSVGStrPoints(rtl::OUString::createFromAscii("points")); + static rtl::OUString aSVGStrDx(rtl::OUString::createFromAscii("dx")); + static rtl::OUString aSVGStrDy(rtl::OUString::createFromAscii("dy")); + static rtl::OUString aSVGStrRotate(rtl::OUString::createFromAscii("rotate")); + static rtl::OUString aSVGStrTextLength(rtl::OUString::createFromAscii("textLength")); + static rtl::OUString aSVGStrLengthAdjust(rtl::OUString::createFromAscii("lengthAdjust")); + static rtl::OUString aSVGStrFont(rtl::OUString::createFromAscii("font")); + static rtl::OUString aSVGStrFontFamily(rtl::OUString::createFromAscii("font-family")); + static rtl::OUString aSVGStrFontSize(rtl::OUString::createFromAscii("font-size")); + static rtl::OUString aSVGStrFontSizeAdjust(rtl::OUString::createFromAscii("font-size-adjust")); + static rtl::OUString aSVGStrFontStretch(rtl::OUString::createFromAscii("font-stretch")); + static rtl::OUString aSVGStrFontStyle(rtl::OUString::createFromAscii("font-style")); + static rtl::OUString aSVGStrFontVariant(rtl::OUString::createFromAscii("font-variant")); + static rtl::OUString aSVGStrFontWeight(rtl::OUString::createFromAscii("font-weight")); + static rtl::OUString aSVGStrDirection(rtl::OUString::createFromAscii("direction")); + static rtl::OUString aSVGStrLetterSpacing(rtl::OUString::createFromAscii("letter-spacing")); + static rtl::OUString aSVGStrTextDecoration(rtl::OUString::createFromAscii("text-decoration")); + static rtl::OUString aSVGStrUnicodeBidi(rtl::OUString::createFromAscii("unicode-bidi")); + static rtl::OUString aSVGStrWordSpacing(rtl::OUString::createFromAscii("word-spacing")); + static rtl::OUString aSVGStrTspan(rtl::OUString::createFromAscii("tspan")); + static rtl::OUString aSVGStrTref(rtl::OUString::createFromAscii("tref")); + static rtl::OUString aSVGStrTextPath(rtl::OUString::createFromAscii("textPath")); + static rtl::OUString aSVGStrStartOffset(rtl::OUString::createFromAscii("startOffset")); + static rtl::OUString aSVGStrMethod(rtl::OUString::createFromAscii("method")); + static rtl::OUString aSVGStrSpacing(rtl::OUString::createFromAscii("spacing")); + static rtl::OUString aSVGStrTextAlign(rtl::OUString::createFromAscii("text-align")); + static rtl::OUString aSVGStrPathLength(rtl::OUString::createFromAscii("pathLength")); + static rtl::OUString aSVGStrType(rtl::OUString::createFromAscii("type")); + static rtl::OUString aSVGStrClass(rtl::OUString::createFromAscii("class")); + static rtl::OUString aSVGStrTextAnchor(rtl::OUString::createFromAscii("text-anchor")); + static rtl::OUString aSVGStrXmlSpace(rtl::OUString::createFromAscii("xml:space")); + static rtl::OUString aSVGStrColor(rtl::OUString::createFromAscii("color")); + static rtl::OUString aSVGStrClipPathNode(rtl::OUString::createFromAscii("clipPath")); + static rtl::OUString aSVGStrClipPathProperty(rtl::OUString::createFromAscii("clip-path")); + static rtl::OUString aSVGStrMask(rtl::OUString::createFromAscii("mask")); + static rtl::OUString aSVGStrClipPathUnits(rtl::OUString::createFromAscii("clipPathUnits")); + static rtl::OUString aSVGStrMaskUnits(rtl::OUString::createFromAscii("maskUnits")); + static rtl::OUString aSVGStrMaskContentUnits(rtl::OUString::createFromAscii("maskContentUnits")); + static rtl::OUString aSVGStrClipRule(rtl::OUString::createFromAscii("clip-rule")); + static rtl::OUString aSVGStrMarker(rtl::OUString::createFromAscii("marker")); + static rtl::OUString aSVGStrMarkerStart(rtl::OUString::createFromAscii("marker-start")); + static rtl::OUString aSVGStrMarkerMid(rtl::OUString::createFromAscii("marker-mid")); + static rtl::OUString aSVGStrMarkerEnd(rtl::OUString::createFromAscii("marker-end")); + static rtl::OUString aSVGStrRefX(rtl::OUString::createFromAscii("refX")); + static rtl::OUString aSVGStrRefY(rtl::OUString::createFromAscii("refY")); + static rtl::OUString aSVGStrMarkerUnits(rtl::OUString::createFromAscii("markerUnits")); + static rtl::OUString aSVGStrMarkerWidth(rtl::OUString::createFromAscii("markerWidth")); + static rtl::OUString aSVGStrMarkerHeight(rtl::OUString::createFromAscii("markerHeight")); + static rtl::OUString aSVGStrOrient(rtl::OUString::createFromAscii("orient")); + static rtl::OUString aSVGStrPattern(rtl::OUString::createFromAscii("pattern")); + static rtl::OUString aSVGStrPatternUnits(rtl::OUString::createFromAscii("patternUnits")); + static rtl::OUString aSVGStrPatternContentUnits(rtl::OUString::createFromAscii("patternContentUnits")); + static rtl::OUString aSVGStrPatternTransform(rtl::OUString::createFromAscii("patternTransform")); + static rtl::OUString aSVGStrOpacity(rtl::OUString::createFromAscii("opacity")); + + static rtl::OUString aSVGStrPreserveAspectRatio(rtl::OUString::createFromAscii("preserveAspectRatio")); + static rtl::OUString aSVGStrDefer(rtl::OUString::createFromAscii("defer")); + static rtl::OUString aSVGStrNone(rtl::OUString::createFromAscii("none")); + static rtl::OUString aSVGStrXMinYMin(rtl::OUString::createFromAscii("xMinYMin")); + static rtl::OUString aSVGStrXMidYMin(rtl::OUString::createFromAscii("xMidYMin")); + static rtl::OUString aSVGStrXMaxYMin(rtl::OUString::createFromAscii("xMaxYMin")); + static rtl::OUString aSVGStrXMinYMid(rtl::OUString::createFromAscii("xMinYMid")); + static rtl::OUString aSVGStrXMidYMid(rtl::OUString::createFromAscii("xMidYMid")); + static rtl::OUString aSVGStrXMaxYMid(rtl::OUString::createFromAscii("xMaxYMid")); + static rtl::OUString aSVGStrXMinYMax(rtl::OUString::createFromAscii("xMinYMax")); + static rtl::OUString aSVGStrXMidYMax(rtl::OUString::createFromAscii("xMidYMax")); + static rtl::OUString aSVGStrXMaxYMax(rtl::OUString::createFromAscii("xMaxYMax")); + static rtl::OUString aSVGStrMeet(rtl::OUString::createFromAscii("meet")); + static rtl::OUString aSVGStrSlice(rtl::OUString::createFromAscii("slice")); + + static rtl::OUString aSVGStrDefs(rtl::OUString::createFromAscii("defs")); + static rtl::OUString aSVGStrG(rtl::OUString::createFromAscii("g")); + static rtl::OUString aSVGStrSvg(rtl::OUString::createFromAscii("svg")); + static rtl::OUString aSVGStrSymbol(rtl::OUString::createFromAscii("symbol")); + static rtl::OUString aSVGStrUse(rtl::OUString::createFromAscii("use")); + + static rtl::OUString aSVGStrCircle(rtl::OUString::createFromAscii("circle")); + static rtl::OUString aSVGStrEllipse(rtl::OUString::createFromAscii("ellipse")); + static rtl::OUString aSVGStrLine(rtl::OUString::createFromAscii("line")); + static rtl::OUString aSVGStrPath(rtl::OUString::createFromAscii("path")); + static rtl::OUString aSVGStrPolygon(rtl::OUString::createFromAscii("polygon")); + static rtl::OUString aSVGStrPolyline(rtl::OUString::createFromAscii("polyline")); + static rtl::OUString aSVGStrRect(rtl::OUString::createFromAscii("rect")); + static rtl::OUString aSVGStrImage(rtl::OUString::createFromAscii("image")); + + static rtl::OUString aSVGStrLinearGradient(rtl::OUString::createFromAscii("linearGradient")); + static rtl::OUString aSVGStrRadialGradient(rtl::OUString::createFromAscii("radialGradient")); + static rtl::OUString aSVGStrStop(rtl::OUString::createFromAscii("stop")); + static rtl::OUString aSVGStrOffset(rtl::OUString::createFromAscii("offset")); + static rtl::OUString aSVGStrX1(rtl::OUString::createFromAscii("x1")); + static rtl::OUString aSVGStrY1(rtl::OUString::createFromAscii("y1")); + static rtl::OUString aSVGStrX2(rtl::OUString::createFromAscii("x2")); + static rtl::OUString aSVGStrY2(rtl::OUString::createFromAscii("y2")); + static rtl::OUString aSVGStrCx(rtl::OUString::createFromAscii("cx")); + static rtl::OUString aSVGStrCy(rtl::OUString::createFromAscii("cy")); + static rtl::OUString aSVGStrFx(rtl::OUString::createFromAscii("fx")); + static rtl::OUString aSVGStrFy(rtl::OUString::createFromAscii("fy")); + static rtl::OUString aSVGStrR(rtl::OUString::createFromAscii("r")); + static rtl::OUString aSVGStrGradientUnits(rtl::OUString::createFromAscii("gradientUnits")); + static rtl::OUString aSVGStrGradientTransform(rtl::OUString::createFromAscii("gradientTransform")); + static rtl::OUString aSVGStrSpreadMethod(rtl::OUString::createFromAscii("spreadMethod")); + static rtl::OUString aSVGStrXlinkHref(rtl::OUString::createFromAscii("xlink:href")); + static rtl::OUString aSVGStrStopColor(rtl::OUString::createFromAscii("stop-color")); + static rtl::OUString aSVGStrStopOpacity(rtl::OUString::createFromAscii("stop-opacity")); + + static rtl::OUString aSVGStrFill(rtl::OUString::createFromAscii("fill")); + static rtl::OUString aSVGStrFillOpacity(rtl::OUString::createFromAscii("fill-opacity")); + static rtl::OUString aSVGStrFillRule(rtl::OUString::createFromAscii("fill-rule")); + + static rtl::OUString aSVGStrStroke(rtl::OUString::createFromAscii("stroke")); + static rtl::OUString aSVGStrStrokeDasharray(rtl::OUString::createFromAscii("stroke-dasharray")); + static rtl::OUString aSVGStrStrokeDashoffset(rtl::OUString::createFromAscii("stroke-dashoffset")); + static rtl::OUString aSVGStrStrokeLinecap(rtl::OUString::createFromAscii("stroke-linecap")); + static rtl::OUString aSVGStrStrokeLinejoin(rtl::OUString::createFromAscii("stroke-linejoin")); + static rtl::OUString aSVGStrStrokeMiterlimit(rtl::OUString::createFromAscii("stroke-miterlimit")); + static rtl::OUString aSVGStrStrokeOpacity(rtl::OUString::createFromAscii("stroke-opacity")); + static rtl::OUString aSVGStrStrokeWidth(rtl::OUString::createFromAscii("stroke-width")); + + static rtl::OUString aSVGStrText(rtl::OUString::createFromAscii("text")); + + SVGToken StrToSVGToken(const rtl::OUString& rStr) + { + typedef boost::unordered_map< rtl::OUString, SVGToken, rtl::OUStringHash,::std::equal_to< ::rtl::OUString > > SVGTokenMapper; + typedef std::pair< rtl::OUString, SVGToken > SVGTokenValueType; + static SVGTokenMapper aSVGTokenMapperList; + + if(aSVGTokenMapperList.empty()) + { + aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrWidth, SVGTokenWidth)); + aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrHeight, SVGTokenHeight)); + aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrViewBox, SVGTokenViewBox)); + aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrTransform, SVGTokenTransform)); + aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrStyle, SVGTokenStyle)); + aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrD, SVGTokenD)); + aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrX, SVGTokenX)); + aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrY, SVGTokenY)); + aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrXmlns, SVGTokenXmlns)); + aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrVersion, SVGTokenVersion)); + aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrId, SVGTokenId)); + aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrRx, SVGTokenRx)); + aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrRy, SVGTokenRy)); + aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrPoints, SVGTokenPoints)); + aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrDx, SVGTokenDx)); + aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrDy, SVGTokenDy)); + aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrRotate, SVGTokenRotate)); + aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrFont, SVGTokenFont)); + aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrFontFamily, SVGTokenFontFamily)); + aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrFontSize, SVGTokenFontSize)); + aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrFontSizeAdjust, SVGTokenFontSizeAdjust)); + aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrFontStretch, SVGTokenFontStretch)); + aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrFontStyle, SVGTokenFontStyle)); + aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrFontVariant, SVGTokenFontVariant)); + aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrFontWeight, SVGTokenFontWeight)); + aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrDirection, SVGTokenDirection)); + aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrLetterSpacing, SVGTokenLetterSpacing)); + aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrTextDecoration, SVGTokenTextDecoration)); + aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrUnicodeBidi, SVGTokenUnicodeBidi)); + aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrWordSpacing, SVGTokenWordSpacing)); + aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrTspan, SVGTokenTspan)); + aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrTref, SVGTokenTref)); + aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrTextPath, SVGTokenTextPath)); + aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrStartOffset, SVGTokenStartOffset)); + aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrMethod, SVGTokenMethod)); + aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrSpacing, SVGTokenSpacing)); + aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrTextAlign, SVGTokenTextAlign)); + aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrPathLength, SVGTokenPathLength)); + aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrType, SVGTokenType)); + aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrClass, SVGTokenClass)); + aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrTextAnchor, SVGTokenTextAnchor)); + aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrXmlSpace, SVGTokenXmlSpace)); + aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrColor, SVGTokenColor)); + aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrClipPathNode, SVGTokenClipPathNode)); + aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrClipPathProperty, SVGTokenClipPathProperty)); + aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrMask, SVGTokenMask)); + aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrClipPathUnits, SVGTokenClipPathUnits)); + aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrMaskUnits, SVGTokenMaskUnits)); + aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrMaskContentUnits, SVGTokenMaskContentUnits)); + aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrClipRule, SVGTokenClipRule)); + aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrMarker, SVGTokenMarker)); + aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrMarkerStart, SVGTokenMarkerStart)); + aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrMarkerMid, SVGTokenMarkerMid)); + aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrMarkerEnd, SVGTokenMarkerEnd)); + aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrRefX, SVGTokenRefX)); + aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrRefY, SVGTokenRefY)); + aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrMarkerUnits, SVGTokenMarkerUnits)); + aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrMarkerWidth, SVGTokenMarkerWidth)); + aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrMarkerHeight, SVGTokenMarkerHeight)); + aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrOrient, SVGTokenOrient)); + aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrPattern, SVGTokenPattern)); + aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrPatternUnits, SVGTokenPatternUnits)); + aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrPatternContentUnits, SVGTokenPatternContentUnits)); + aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrPatternTransform, SVGTokenPatternTransform)); + aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrOpacity, SVGTokenOpacity)); + + aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrPreserveAspectRatio, SVGTokenPreserveAspectRatio)); + aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrDefer, SVGTokenDefer)); + aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrNone, SVGTokenNone)); + aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrXMinYMin, SVGTokenXMinYMin)); + aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrXMidYMin, SVGTokenXMidYMin)); + aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrXMaxYMin, SVGTokenXMaxYMin)); + aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrXMinYMid, SVGTokenXMinYMid)); + aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrXMidYMid, SVGTokenXMidYMid)); + aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrXMaxYMid, SVGTokenXMaxYMid)); + aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrXMinYMax, SVGTokenXMinYMax)); + aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrXMidYMax, SVGTokenXMidYMax)); + aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrXMaxYMax, SVGTokenXMaxYMax)); + aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrMeet, SVGTokenMeet)); + aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrSlice, SVGTokenSlice)); + + aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrDefs, SVGTokenDefs)); + aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrG, SVGTokenG)); + aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrSvg, SVGTokenSvg)); + aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrSymbol, SVGTokenSymbol)); + aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrUse, SVGTokenUse)); + + aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrCircle, SVGTokenCircle)); + aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrEllipse, SVGTokenEllipse)); + aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrLine, SVGTokenLine)); + aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrPath, SVGTokenPath)); + aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrPolygon, SVGTokenPolygon)); + aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrPolyline, SVGTokenPolyline)); + aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrRect, SVGTokenRect)); + aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrImage, SVGTokenImage)); + + aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrLinearGradient, SVGTokenLinearGradient)); + aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrRadialGradient, SVGTokenRadialGradient)); + aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrStop, SVGTokenStop)); + aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrOffset, SVGTokenOffset)); + aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrX1, SVGTokenX1)); + aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrY1, SVGTokenY1)); + aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrX2, SVGTokenX2)); + aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrY2, SVGTokenY2)); + aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrCx, SVGTokenCx)); + aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrCy, SVGTokenCy)); + aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrFx, SVGTokenFx)); + aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrFy, SVGTokenFy)); + aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrR, SVGTokenR)); + aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrGradientUnits, SVGTokenGradientUnits)); + aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrGradientTransform, SVGTokenGradientTransform)); + aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrSpreadMethod, SVGTokenSpreadMethod)); + aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrXlinkHref, SVGTokenXlinkHref)); + aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrStopColor, SVGTokenStopColor)); + aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrStopOpacity, SVGTokenStopOpacity)); + + aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrFill, SVGTokenFill)); + aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrFillOpacity, SVGTokenFillOpacity)); + aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrFillRule, SVGTokenFillRule)); + + aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrStroke, SVGTokenStroke)); + aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrStrokeDasharray, SVGTokenStrokeDasharray)); + aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrStrokeDashoffset, SVGTokenStrokeDashoffset)); + aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrStrokeLinecap, SVGTokenStrokeLinecap)); + aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrStrokeLinejoin, SVGTokenStrokeLinejoin)); + aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrStrokeMiterlimit, SVGTokenStrokeMiterlimit)); + aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrStrokeOpacity, SVGTokenStrokeOpacity)); + aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrStrokeWidth, SVGTokenStrokeWidth)); + + aSVGTokenMapperList.insert(SVGTokenValueType(aSVGStrText, SVGTokenText)); + } + + const SVGTokenMapper::const_iterator aResult(aSVGTokenMapperList.find(rStr)); + + if(aResult == aSVGTokenMapperList.end()) + { + return SVGTokenUnknown; + } + else + { + return aResult->second; + } + } + } // end of namespace svgreader +} // end of namespace svgio + +////////////////////////////////////////////////////////////////////////////// +// eof + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svgio/source/svgreader/svgtools.cxx b/svgio/source/svgreader/svgtools.cxx new file mode 100644 index 000000000000..ae0df2fca7c9 --- /dev/null +++ b/svgio/source/svgreader/svgtools.cxx @@ -0,0 +1,1592 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <svgio/svgreader/svgtools.hxx> +#include <osl/thread.h> +#include <tools/color.hxx> +#include <basegfx/matrix/b2dhommatrix.hxx> +#include <basegfx/matrix/b2dhommatrixtools.hxx> +#include <svgio/svgreader/svgtoken.hxx> +#include <boost/unordered_map.hpp> + +////////////////////////////////////////////////////////////////////////////// + +namespace svgio +{ + namespace svgreader + { +#ifdef DBG_UTIL + void myAssert(const rtl::OUString& rMessage) + { + rtl::OString aMessage2; + + rMessage.convertToString(&aMessage2, osl_getThreadTextEncoding(), RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR|RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR); + OSL_ENSURE(false, aMessage2.getStr()); + } +#endif + + // common non-token strings + const rtl::OUString commonStrings::aStrUserSpaceOnUse(rtl::OUString::createFromAscii("userSpaceOnUse")); + const rtl::OUString commonStrings::aStrObjectBoundingBox(rtl::OUString::createFromAscii("objectBoundingBox")); + const rtl::OUString commonStrings::aStrNonzero(rtl::OUString::createFromAscii("nonzero")); + const rtl::OUString commonStrings::aStrEvenOdd(rtl::OUString::createFromAscii("evenodd")); + + basegfx::B2DHomMatrix SvgAspectRatio::createLinearMapping(const basegfx::B2DRange& rTarget, const basegfx::B2DRange& rSource) + { + basegfx::B2DHomMatrix aRetval; + const double fSWidth(rSource.getWidth()); + const double fSHeight(rSource.getHeight()); + const bool bNoSWidth(basegfx::fTools::equalZero(fSWidth)); + const bool bNoSHeight(basegfx::fTools::equalZero(fSHeight)); + + // transform from source state to unit range + aRetval.translate(-rSource.getMinX(), -rSource.getMinY()); + aRetval.scale( + (bNoSWidth ? 1.0 : 1.0 / fSWidth) * rTarget.getWidth(), + (bNoSHeight ? 1.0 : 1.0 / fSHeight) * rTarget.getHeight()); + + // transform from unit rage to target range + aRetval.translate(rTarget.getMinX(), rTarget.getMinY()); + + return aRetval; + } + + basegfx::B2DHomMatrix SvgAspectRatio::createMapping(const basegfx::B2DRange& rTarget, const basegfx::B2DRange& rSource) const + { + if(!isSet() || Align_none == getSvgAlign()) + { + // create linear mapping (default) + return createLinearMapping(rTarget, rSource); + } + + basegfx::B2DHomMatrix aRetval; + + const double fSWidth(rSource.getWidth()); + const double fSHeight(rSource.getHeight()); + const bool bNoSWidth(basegfx::fTools::equalZero(fSWidth)); + const bool bNoSHeight(basegfx::fTools::equalZero(fSHeight)); + const double fScaleX((bNoSWidth ? 1.0 : 1.0 / fSWidth) * rTarget.getWidth()); + const double fScaleY((bNoSHeight ? 1.0 : 1.0 / fSHeight) * rTarget.getHeight()); + const double fScale(isMeetOrSlice() ? std::min(fScaleX, fScaleY) : std::max(fScaleX, fScaleY)); + + // remove source translation, apply scale + aRetval.translate(-rSource.getMinX(), -rSource.getMinY()); + aRetval.scale(fScale, fScale); + + // evaluate horizontal alignment + const double fNewWidth(fSWidth * fScale); + double fTransX(0.0); + + switch(getSvgAlign()) + { + case Align_xMidYMin: + case Align_xMidYMid: + case Align_xMidYMax: + { + // centerX + const double fFreeSpace(rTarget.getWidth() - fNewWidth); + fTransX = fFreeSpace * 0.5; + break; + } + case Align_xMaxYMin: + case Align_xMaxYMid: + case Align_xMaxYMax: + { + // Right align + const double fFreeSpace(rTarget.getWidth() - fNewWidth); + fTransX = fFreeSpace; + break; + } + default: break; + } + + // evaluate vertical alignment + const double fNewHeight(fSHeight * fScale); + double fTransY(0.0); + + switch(getSvgAlign()) + { + case Align_xMinYMid: + case Align_xMidYMid: + case Align_xMaxYMid: + { + // centerY + const double fFreeSpace(rTarget.getHeight() - fNewHeight); + fTransY = fFreeSpace * 0.5; + break; + } + case Align_xMinYMax: + case Align_xMidYMax: + case Align_xMaxYMax: + { + // Bottom align + const double fFreeSpace(rTarget.getHeight() - fNewHeight); + fTransY = fFreeSpace; + break; + } + default: break; + } + + // add target translation + aRetval.translate( + rTarget.getMinX() + fTransX, + rTarget.getMinY() + fTransY); + + return aRetval; + } + + double SvgNumber::solve(const InfoProvider& rInfoProvider, NumberType aNumberType) const + { + if(isSet()) + { + switch(meUnit) + { + case Unit_em: + { + return mfNumber * rInfoProvider.getCurrentFontSize(); + break; + } + case Unit_ex: + { + return mfNumber * rInfoProvider.getCurrentXHeight() * 0.5; + break; + } + case Unit_px: + { + return mfNumber; + break; + } + case Unit_pt: + case Unit_pc: + case Unit_cm: + case Unit_mm: + case Unit_in: + { + double fRetval(mfNumber); + + switch(meUnit) + { + case Unit_pt: fRetval *= 1.25; break; + case Unit_pc: fRetval *= 15.0; break; + case Unit_cm: fRetval *= 35.43307; break; + case Unit_mm: fRetval *= 3.543307; break; + case Unit_in: fRetval *= 90.0; break; + default: break; + } + + return fRetval; + break; + } + case Unit_percent: + { + double fRetval(mfNumber * 0.01); + const basegfx::B2DRange* pViewPort = rInfoProvider.getCurrentViewPort(); + + if(!pViewPort) + { + // no viewPort, assume a normal page size (A4) + static basegfx::B2DRange aDinA4Range( + 0.0, + 0.0, + 210.0 * 3.543307, + 297.0 * 3.543307); + + pViewPort = &aDinA4Range; + } + + if(pViewPort) + { + if(xcoordinate == aNumberType) + { + // it's a x-coordinate, relative to current width (w) + fRetval *= pViewPort->getWidth(); + } + else if(ycoordinate == aNumberType) + { + // it's a y-coordinate, relative to current height (h) + fRetval *= pViewPort->getHeight(); + } + else // length + { + // it's a length, relative to sqrt(w*w + h*h)/sqrt(2) + const double fCurrentWidth(pViewPort->getWidth()); + const double fCurrentHeight(pViewPort->getHeight()); + const double fCurrentLength( + sqrt(fCurrentWidth * fCurrentWidth + fCurrentHeight * fCurrentHeight)/sqrt(2.0)); + + fRetval *= fCurrentLength; + } + } + + return fRetval; + break; + } + default: + { + break; + } + } + } + + /// not set + OSL_ENSURE(false, "SvgNumber not set (!)"); + return 0.0; + } + + bool SvgNumber::isPositive() const + { + return basegfx::fTools::moreOrEqual(mfNumber, 0.0); + } + + void skip_char(const rtl::OUString& rCandidate, const sal_Unicode& rChar, sal_Int32& nPos, const sal_Int32 nLen) + { + while(nPos < nLen && rChar == rCandidate[nPos]) + { + nPos++; + } + } + + void skip_char(const rtl::OUString& rCandidate, const sal_Unicode& rCharA, const sal_Unicode& rCharB, sal_Int32& nPos, const sal_Int32 nLen) + { + while(nPos < nLen && (rCharA == rCandidate[nPos] || rCharB == rCandidate[nPos])) + { + nPos++; + } + } + + void copySign(const rtl::OUString& rCandidate, sal_Int32& nPos, rtl::OUStringBuffer& rTarget, const sal_Int32 nLen) + { + if(nPos < nLen) + { + const sal_Unicode aChar(rCandidate[nPos]); + + if(sal_Unicode('+') == aChar || sal_Unicode('-') == aChar) + { + rTarget.append(aChar); + nPos++; + } + } + } + + void copyNumber(const rtl::OUString& rCandidate, sal_Int32& nPos, rtl::OUStringBuffer& rTarget, const sal_Int32 nLen) + { + bool bOnNumber(true); + + while(bOnNumber && nPos < nLen) + { + const sal_Unicode aChar(rCandidate[nPos]); + + bOnNumber = (sal_Unicode('0') <= aChar && sal_Unicode('9') >= aChar) || sal_Unicode('.') == aChar; + + if(bOnNumber) + { + rTarget.append(aChar); + nPos++; + } + } + } + + void copyHex(const rtl::OUString& rCandidate, sal_Int32& nPos, rtl::OUStringBuffer& rTarget, const sal_Int32 nLen) + { + bool bOnHex(true); + + while(bOnHex && nPos < nLen) + { + const sal_Unicode aChar(rCandidate[nPos]); + + bOnHex = (sal_Unicode('0') <= aChar && sal_Unicode('9') >= aChar) + || (sal_Unicode('A') <= aChar && sal_Unicode('F') >= aChar) + || (sal_Unicode('a') <= aChar && sal_Unicode('f') >= aChar); + + if(bOnHex) + { + rTarget.append(aChar); + nPos++; + } + } + } + + void copyString(const rtl::OUString& rCandidate, sal_Int32& nPos, rtl::OUStringBuffer& rTarget, const sal_Int32 nLen) + { + bool bOnChar(true); + + while(bOnChar && nPos < nLen) + { + const sal_Unicode aChar(rCandidate[nPos]); + + bOnChar = (sal_Unicode('a') <= aChar && sal_Unicode('z') >= aChar) + || (sal_Unicode('A') <= aChar && sal_Unicode('Z') >= aChar) + || sal_Unicode('-') == aChar; + + if(bOnChar) + { + rTarget.append(aChar); + nPos++; + } + } + } + + void copyToLimiter(const rtl::OUString& rCandidate, const sal_Unicode& rLimiter, sal_Int32& nPos, rtl::OUStringBuffer& rTarget, const sal_Int32 nLen) + { + while(nPos < nLen && rLimiter != rCandidate[nPos]) + { + rTarget.append(rCandidate[nPos]); + nPos++; + } + } + + bool readNumber(const rtl::OUString& rCandidate, sal_Int32& nPos, double& fNum, const sal_Int32 nLen) + { + if(nPos < nLen) + { + rtl::OUStringBuffer aNum; + + copySign(rCandidate, nPos, aNum, nLen); + copyNumber(rCandidate, nPos, aNum, nLen); + + if(nPos < nLen) + { + const sal_Unicode aChar(rCandidate[nPos]); + + if(sal_Unicode('e') == aChar || sal_Unicode('E') == aChar) + { + // try to read exponential number, but be careful. I had + // a case where dx="2em" was used, thus the 'e' was consumed + // by error. First try if there are numbers after the 'e', + // safe current state + nPos++; + const rtl::OUStringBuffer aNum2(aNum); + const sal_Int32 nPosAfterE(nPos); + + aNum.append(aChar); + copySign(rCandidate, nPos, aNum, nLen); + copyNumber(rCandidate, nPos, aNum, nLen); + + if(nPosAfterE == nPos) + { + // no number after 'e', go back. Do not + // return false, it's still a valid integer number + aNum = aNum2; + nPos--; + } + } + } + + if(aNum.getLength()) + { + rtl_math_ConversionStatus eStatus; + + fNum = rtl::math::stringToDouble( + aNum.makeStringAndClear(), (sal_Unicode)('.'), (sal_Unicode)(','), + &eStatus, 0); + + return eStatus == rtl_math_ConversionStatus_Ok; + } + } + + return false; + } + + SvgUnit readUnit(const rtl::OUString& rCandidate, sal_Int32& nPos, const sal_Int32 nLen) + { + SvgUnit aRetval(Unit_px); + + if(nPos < nLen) + { + const sal_Unicode aCharA(rCandidate[nPos]); + + if(nPos + 1 < nLen) + { + const sal_Unicode aCharB(rCandidate[nPos + 1]); + bool bTwoCharValid(false); + + switch(aCharA) + { + case sal_Unicode('e') : + { + if(sal_Unicode('m') == aCharB) + { + // 'em' Relative to current font size + aRetval = Unit_em; + bTwoCharValid = true; + } + else if(sal_Unicode('x') == aCharB) + { + // 'ex' Relative to current font x-height + aRetval = Unit_ex; + bTwoCharValid = true; + } + break; + } + case sal_Unicode('p') : + { + if(sal_Unicode('x') == aCharB) + { + // 'px' UserUnit (default) + bTwoCharValid = true; + } + else if(sal_Unicode('t') == aCharB) + { + // 'pt' == 1.25 px + aRetval = Unit_pt; + bTwoCharValid = true; + } + else if(sal_Unicode('c') == aCharB) + { + // 'pc' == 15 px + aRetval = Unit_pc; + bTwoCharValid = true; + } + break; + } + case sal_Unicode('i') : + { + if(sal_Unicode('n') == aCharB) + { + // 'in' == 90 px + aRetval = Unit_in; + bTwoCharValid = true; + } + break; + } + case sal_Unicode('c') : + { + if(sal_Unicode('m') == aCharB) + { + // 'cm' == 35.43307 px + aRetval = Unit_cm; + bTwoCharValid = true; + } + break; + } + case sal_Unicode('m') : + { + if(sal_Unicode('m') == aCharB) + { + // 'mm' == 3.543307 px + aRetval = Unit_mm; + bTwoCharValid = true; + } + break; + } + } + + if(bTwoCharValid) + { + nPos += 2; + } + } + else + { + if(sal_Unicode('%') == aCharA) + { + // percent used, relative to current + nPos++; + aRetval = Unit_percent; + } + } + } + + return aRetval; + } + + bool readNumberAndUnit(const rtl::OUString& rCandidate, sal_Int32& nPos, SvgNumber& aNum, const sal_Int32 nLen) + { + double fNum(0.0); + + if(readNumber(rCandidate, nPos, fNum, nLen)) + { + skip_char(rCandidate, sal_Unicode(' '), nPos, nLen); + aNum = SvgNumber(fNum, readUnit(rCandidate, nPos, nLen)); + + return true; + } + + return false; + } + + bool readAngle(const rtl::OUString& rCandidate, sal_Int32& nPos, double& fAngle, const sal_Int32 nLen) + { + if(readNumber(rCandidate, nPos, fAngle, nLen)) + { + skip_char(rCandidate, sal_Unicode(' '), nPos, nLen); + + enum DegreeType + { + deg, + grad, + rad + } aType(deg); // degrees is default + + if(nPos < nLen) + { + const sal_Unicode aChar(rCandidate[nPos]); + static rtl::OUString aStrGrad(rtl::OUString::createFromAscii("grad")); + static rtl::OUString aStrRad(rtl::OUString::createFromAscii("rad")); + + switch(aChar) + { + case sal_Unicode('g') : + case sal_Unicode('G') : + { + if(rCandidate.matchIgnoreAsciiCase(aStrGrad, nPos)) + { + // angle in grad + nPos += aStrGrad.getLength(); + } + break; + } + case sal_Unicode('r') : + case sal_Unicode('R') : + { + if(rCandidate.matchIgnoreAsciiCase(aStrRad, nPos)) + { + // angle in radians + nPos += aStrRad.getLength(); + } + break; + } + } + } + + // convert to radians + if(deg == aType) + { + fAngle *= F_PI / 180.0; + } + else if(grad == aType) + { + // looks like 100 grad is 90 degrees + fAngle *= F_PI / 200.0; + } + + return true; + } + + return false; + } + + sal_Int32 read_hex(const sal_Unicode& rChar) + { + if(rChar >= sal_Unicode('0') && rChar <=sal_Unicode('9')) + { + return sal_Int32(rChar - sal_Unicode('0')); + } + else if(rChar >= sal_Unicode('A') && rChar <=sal_Unicode('F')) + { + return 10 + sal_Int32(rChar - sal_Unicode('A')); + } + else if(rChar >= sal_Unicode('a') && rChar <=sal_Unicode('f')) + { + return 10 + sal_Int32(rChar - sal_Unicode('a')); + } + else + { + // error + return 0; + } + } + + bool match_colorKeyword(basegfx::BColor& rColor, const rtl::OUString& rName) + { + typedef boost::unordered_map< rtl::OUString, Color, + rtl::OUStringHash, + ::std::equal_to< ::rtl::OUString > + > ColorTokenMapper; + typedef std::pair< rtl::OUString, Color > ColorTokenValueType; + ColorTokenMapper aColorTokenMapperList; + + if(aColorTokenMapperList.empty()) + { + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("aliceblue"), Color(240, 248, 255))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("antiquewhite"), Color(250, 235, 215))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("aqua"), Color( 0, 255, 255))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("aquamarine"), Color(127, 255, 212))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("azure"), Color(240, 255, 255))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("beige"), Color(245, 245, 220))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("bisque"), Color(255, 228, 196))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("black"), Color( 0, 0, 0))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("blanchedalmond"), Color(255, 235, 205))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("blue"), Color( 0, 0, 255))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("blueviolet"), Color(138, 43, 226))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("brown"), Color(165, 42, 42))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("burlywood"), Color(222, 184, 135))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("cadetblue"), Color( 95, 158, 160))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("chartreuse"), Color(127, 255, 0))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("chocolate"), Color(210, 105, 30))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("coral"), Color(255, 127, 80))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("cornflowerblue"), Color(100, 149, 237))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("cornsilk"), Color(255, 248, 220))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("crimson"), Color(220, 20, 60))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("cyan"), Color( 0, 255, 255))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("darkblue"), Color( 0, 0, 139))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("darkcyan"), Color( 0, 139, 139))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("darkgoldenrod"), Color(184, 134, 11))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("darkgray"), Color(169, 169, 169))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("darkgreen"), Color( 0, 100, 0))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("darkgrey"), Color(169, 169, 169))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("darkkhaki"), Color(189, 183, 107))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("darkmagenta"), Color(139, 0, 139))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("darkolivegreen"), Color( 85, 107, 47))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("darkorange"), Color(255, 140, 0))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("darkorchid"), Color(153, 50, 204))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("darkred"), Color(139, 0, 0))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("darksalmon"), Color(233, 150, 122))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("darkseagreen"), Color(143, 188, 143))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("darkslateblue"), Color( 72, 61, 139))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("darkslategray"), Color( 47, 79, 79))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("darkslategrey"), Color( 47, 79, 79))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("darkturquoise"), Color( 0, 206, 209))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("darkviolet"), Color(148, 0, 211))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("deeppink"), Color(255, 20, 147))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("deepskyblue"), Color( 0, 191, 255))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("dimgray"), Color(105, 105, 105))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("dimgrey"), Color(105, 105, 105))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("dodgerblue"), Color( 30, 144, 255))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("firebrick"), Color(178, 34, 34))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("floralwhite"), Color(255, 250, 240))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("forestgreen"), Color( 34, 139, 34))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("fuchsia"), Color(255, 0, 255))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("gainsboro"), Color(220, 220, 220))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("ghostwhite"), Color(248, 248, 255))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("gold"), Color(255, 215, 0))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("goldenrod"), Color(218, 165, 32))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("gray"), Color(128, 128, 128))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("grey"), Color(128, 128, 128))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("green"), Color(0, 128, 0))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("greenyellow"), Color(173, 255, 47))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("honeydew"), Color(240, 255, 240))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("hotpink"), Color(255, 105, 180))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("indianred"), Color(205, 92, 92))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("indigo"), Color( 75, 0, 130))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("ivory"), Color(255, 255, 240))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("khaki"), Color(240, 230, 140))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("lavender"), Color(230, 230, 250))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("lavenderblush"), Color(255, 240, 245))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("lawngreen"), Color(124, 252, 0))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("lemonchiffon"), Color(255, 250, 205))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("lightblue"), Color(173, 216, 230))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("lightcoral"), Color(240, 128, 128))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("lightcyan"), Color(224, 255, 255))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("lightgoldenrodyellow"), Color(250, 250, 210))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("lightgray"), Color(211, 211, 211))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("lightgreen"), Color(144, 238, 144))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("lightgrey"), Color(211, 211, 211))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("lightpink"), Color(255, 182, 193))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("lightsalmon"), Color(255, 160, 122))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("lightseagreen"), Color( 32, 178, 170))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("lightskyblue"), Color(135, 206, 250))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("lightslategray"), Color(119, 136, 153))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("lightslategrey"), Color(119, 136, 153))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("lightsteelblue"), Color(176, 196, 222))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("lightyellow"), Color(255, 255, 224))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("lime"), Color( 0, 255, 0))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("limegreen"), Color( 50, 205, 50))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("linen"), Color(250, 240, 230))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("magenta"), Color(255, 0, 255))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("maroon"), Color(128, 0, 0))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("mediumaquamarine"), Color(102, 205, 170))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("mediumblue"), Color( 0, 0, 205))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("mediumorchid"), Color(186, 85, 211))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("mediumpurple"), Color(147, 112, 219))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("mediumseagreen"), Color( 60, 179, 113))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("mediumslateblue"), Color(123, 104, 238))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("mediumspringgreen"), Color( 0, 250, 154))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("mediumturquoise"), Color( 72, 209, 204))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("mediumvioletred"), Color(199, 21, 133))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("midnightblue"), Color( 25, 25, 112))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("mintcream"), Color(245, 255, 250))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("mistyrose"), Color(255, 228, 225))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("moccasin"), Color(255, 228, 181))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("navajowhite"), Color(255, 222, 173))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("navy"), Color( 0, 0, 128))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("oldlace"), Color(253, 245, 230))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("olive"), Color(128, 128, 0))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("olivedrab"), Color(107, 142, 35))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("orange"), Color(255, 165, 0))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("orangered"), Color(255, 69, 0))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("orchid"), Color(218, 112, 214))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("palegoldenrod"), Color(238, 232, 170))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("palegreen"), Color(152, 251, 152))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("paleturquoise"), Color(175, 238, 238))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("palevioletred"), Color(219, 112, 147))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("papayawhip"), Color(255, 239, 213))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("peachpuff"), Color(255, 218, 185))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("peru"), Color(205, 133, 63))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("pink"), Color(255, 192, 203))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("plum"), Color(221, 160, 221))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("powderblue"), Color(176, 224, 230))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("purple"), Color(128, 0, 128))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("red"), Color(255, 0, 0))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("rosybrown"), Color(188, 143, 143))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("royalblue"), Color( 65, 105, 225))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("saddlebrown"), Color(139, 69, 19))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("salmon"), Color(250, 128, 114))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("sandybrown"), Color(244, 164, 96))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("seagreen"), Color( 46, 139, 87))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("seashell"), Color(255, 245, 238))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("sienna"), Color(160, 82, 45))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("silver"), Color(192, 192, 192))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("skyblue"), Color(135, 206, 235))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("slateblue"), Color(106, 90, 205))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("slategray"), Color(112, 128, 144))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("slategrey"), Color(112, 128, 144))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("snow"), Color(255, 250, 250))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("springgreen"), Color( 0, 255, 127))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("steelblue"), Color( 70, 130, 180))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("tan"), Color(210, 180, 140))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("teal"), Color( 0, 128, 128))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("thistle"), Color(216, 191, 216))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("tomato"), Color(255, 99, 71))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("turquoise"), Color( 64, 224, 208))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("violet"), Color(238, 130, 238))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("wheat"), Color(245, 222, 179))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("white"), Color(255, 255, 255))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("whitesmoke"), Color(245, 245, 245))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("yellow"), Color(255, 255, 0))); + aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("yellowgreen"), Color(154, 205, 50))); + } + + const ColorTokenMapper::const_iterator aResult(aColorTokenMapperList.find(rName)); + + if(aResult == aColorTokenMapperList.end()) + { + return false; + } + else + { + rColor = aResult->second.getBColor(); + return true; + } + } + + bool read_color(const rtl::OUString& rCandidate, basegfx::BColor& rColor) + { + const sal_Int32 nLen(rCandidate.getLength()); + + if(nLen) + { + const sal_Unicode aChar(rCandidate[0]); + const double fFactor(1.0 / 255.0); + + if(aChar == sal_Unicode('#')) + { + // hex definition + rtl::OUStringBuffer aNum; + sal_Int32 nPos(1); + + copyHex(rCandidate, nPos, aNum, nLen); + const sal_Int32 nLength(aNum.getLength()); + + if(3 == nLength) + { + const sal_Int32 nR(read_hex(aNum[0])); + const sal_Int32 nG(read_hex(aNum[1])); + const sal_Int32 nB(read_hex(aNum[2])); + + rColor.setRed((nR | (nR << 4)) * fFactor); + rColor.setGreen((nG | (nG << 4)) * fFactor); + rColor.setBlue((nB | (nB << 4)) * fFactor); + + return true; + } + else if(6 == nLength) + { + const sal_Int32 nR1(read_hex(aNum[0])); + const sal_Int32 nR2(read_hex(aNum[1])); + const sal_Int32 nG1(read_hex(aNum[2])); + const sal_Int32 nG2(read_hex(aNum[3])); + const sal_Int32 nB1(read_hex(aNum[4])); + const sal_Int32 nB2(read_hex(aNum[5])); + + rColor.setRed((nR2 | (nR1 << 4)) * fFactor); + rColor.setGreen((nG2 | (nG1 << 4)) * fFactor); + rColor.setBlue((nB2 | (nB1 << 4)) * fFactor); + + return true; + } + } + else + { + static rtl::OUString aStrRgb(rtl::OUString::createFromAscii("rgb")); + + if(rCandidate.matchIgnoreAsciiCase(aStrRgb, 0)) + { + // rgb definition + sal_Int32 nPos(aStrRgb.getLength()); + skip_char(rCandidate, sal_Unicode(' '), sal_Unicode('('), nPos, nLen); + double fR(0.0); + + if(readNumber(rCandidate, nPos, fR, nLen)) + { + skip_char(rCandidate, sal_Unicode(' '), nPos, nLen); + + if(nPos < nLen) + { + const sal_Unicode aPercentChar(rCandidate[nPos]); + const bool bIsPercent(sal_Unicode('%') == aPercentChar); + double fG(0.0); + + if(bIsPercent) + { + skip_char(rCandidate, sal_Unicode('%'), nPos, nLen); + } + + skip_char(rCandidate, sal_Unicode(' '), sal_Unicode(','), nPos, nLen); + + if(readNumber(rCandidate, nPos, fG, nLen)) + { + double fB(0.0); + + if(bIsPercent) + { + skip_char(rCandidate, sal_Unicode('%'), nPos, nLen); + } + + skip_char(rCandidate, sal_Unicode(' '), sal_Unicode(','), nPos, nLen); + + if(readNumber(rCandidate, nPos, fB, nLen)) + { + const double fFac(bIsPercent ? 0.01 : fFactor); + + rColor.setRed(fR * fFac); + rColor.setGreen(fG * fFac); + rColor.setBlue(fB * fFac); + + if(bIsPercent) + { + skip_char(rCandidate, sal_Unicode('%'), nPos, nLen); + } + + skip_char(rCandidate, sal_Unicode(' '), sal_Unicode(')'), nPos, nLen); + return true; + } + } + } + } + } + else + { + // color keyword + if(match_colorKeyword(rColor, rCandidate)) + { + return true; + } + } + } + } + + return false; + } + + basegfx::B2DRange readViewBox(const rtl::OUString& rCandidate, InfoProvider& rInfoProvider) + { + const sal_Int32 nLen(rCandidate.getLength()); + + if(nLen) + { + sal_Int32 nPos(0); + SvgNumber aMinX; + skip_char(rCandidate, sal_Unicode(' '), sal_Unicode(','), nPos, nLen); + + if(readNumberAndUnit(rCandidate, nPos, aMinX, nLen)) + { + SvgNumber aMinY; + skip_char(rCandidate, sal_Unicode(' '), sal_Unicode(','), nPos, nLen); + + if(readNumberAndUnit(rCandidate, nPos, aMinY, nLen)) + { + SvgNumber aWidth; + skip_char(rCandidate, sal_Unicode(' '), sal_Unicode(','), nPos, nLen); + + if(readNumberAndUnit(rCandidate, nPos, aWidth, nLen)) + { + SvgNumber aHeight; + skip_char(rCandidate, sal_Unicode(' '), sal_Unicode(','), nPos, nLen); + + if(readNumberAndUnit(rCandidate, nPos, aHeight, nLen)) + { + return basegfx::B2DRange( + aMinX.solve(rInfoProvider, xcoordinate), + aMinY.solve(rInfoProvider, ycoordinate), + aWidth.solve(rInfoProvider, xcoordinate), + aHeight.solve(rInfoProvider, ycoordinate)); + } + } + } + } + } + + return basegfx::B2DRange(); + } + + basegfx::B2DHomMatrix readTransform(const rtl::OUString& rCandidate, InfoProvider& rInfoProvider) + { + basegfx::B2DHomMatrix aMatrix; + const sal_Int32 nLen(rCandidate.getLength()); + + if(nLen) + { + sal_Int32 nPos(0); + skip_char(rCandidate, sal_Unicode(' '), sal_Unicode(','), nPos, nLen); + + while(nPos < nLen) + { + const sal_Unicode aChar(rCandidate[nPos]); + const sal_Int32 nInitPos(nPos); + static rtl::OUString aStrMatrix(rtl::OUString::createFromAscii("matrix")); + static rtl::OUString aStrTranslate(rtl::OUString::createFromAscii("translate")); + static rtl::OUString aStrScale(rtl::OUString::createFromAscii("scale")); + static rtl::OUString aStrRotate(rtl::OUString::createFromAscii("rotate")); + static rtl::OUString aStrSkewX(rtl::OUString::createFromAscii("skewX")); + static rtl::OUString aStrSkewY(rtl::OUString::createFromAscii("skewY")); + + switch(aChar) + { + case sal_Unicode('m') : + { + if(rCandidate.match(aStrMatrix, nPos)) + { + // matrix element + nPos += aStrMatrix.getLength(); + skip_char(rCandidate, sal_Unicode(' '), sal_Unicode('('), nPos, nLen); + SvgNumber aVal; + basegfx::B2DHomMatrix aNew; + + if(readNumberAndUnit(rCandidate, nPos, aVal, nLen)) + { + aNew.set(0, 0, aVal.solve(rInfoProvider)); // Element A + skip_char(rCandidate, sal_Unicode(' '), sal_Unicode(','), nPos, nLen); + + if(readNumberAndUnit(rCandidate, nPos, aVal, nLen)) + { + aNew.set(1, 0, aVal.solve(rInfoProvider)); // Element B + skip_char(rCandidate, sal_Unicode(' '), sal_Unicode(','), nPos, nLen); + + if(readNumberAndUnit(rCandidate, nPos, aVal, nLen)) + { + aNew.set(0, 1, aVal.solve(rInfoProvider)); // Element C + skip_char(rCandidate, sal_Unicode(' '), sal_Unicode(','), nPos, nLen); + + if(readNumberAndUnit(rCandidate, nPos, aVal, nLen)) + { + aNew.set(1, 1, aVal.solve(rInfoProvider)); // Element D + skip_char(rCandidate, sal_Unicode(' '), sal_Unicode(','), nPos, nLen); + + if(readNumberAndUnit(rCandidate, nPos, aVal, nLen)) + { + aNew.set(0, 2, aVal.solve(rInfoProvider, xcoordinate)); // Element E + skip_char(rCandidate, sal_Unicode(' '), sal_Unicode(','), nPos, nLen); + + if(readNumberAndUnit(rCandidate, nPos, aVal, nLen)) + { + aNew.set(1, 2, aVal.solve(rInfoProvider, ycoordinate)); // Element F + skip_char(rCandidate, sal_Unicode(' '), sal_Unicode(')'), nPos, nLen); + skip_char(rCandidate, sal_Unicode(' '), sal_Unicode(','), nPos, nLen); + + // caution: String is evaluated from left to right, but matrix multiplication + // in SVG is right to left, so put the new transformation before the current + // one by multiplicating from the right side + aMatrix = aMatrix * aNew; + } + } + } + } + } + } + } + break; + } + case sal_Unicode('t') : + { + if(rCandidate.match(aStrTranslate, nPos)) + { + // translate element + nPos += aStrTranslate.getLength(); + skip_char(rCandidate, sal_Unicode(' '), sal_Unicode('('), nPos, nLen); + SvgNumber aTransX; + + if(readNumberAndUnit(rCandidate, nPos, aTransX, nLen)) + { + skip_char(rCandidate, sal_Unicode(' '), sal_Unicode(','), nPos, nLen); + SvgNumber aTransY; + readNumberAndUnit(rCandidate, nPos, aTransY, nLen); + skip_char(rCandidate, sal_Unicode(' '), sal_Unicode(')'), nPos, nLen); + skip_char(rCandidate, sal_Unicode(' '), sal_Unicode(','), nPos, nLen); + + aMatrix = aMatrix * basegfx::tools::createTranslateB2DHomMatrix( + aTransX.solve(rInfoProvider, xcoordinate), + aTransY.solve(rInfoProvider, ycoordinate)); + } + } + break; + } + case sal_Unicode('s') : + { + if(rCandidate.match(aStrScale, nPos)) + { + // scale element + nPos += aStrScale.getLength(); + skip_char(rCandidate, sal_Unicode(' '), sal_Unicode('('), nPos, nLen); + SvgNumber aScaleX; + + if(readNumberAndUnit(rCandidate, nPos, aScaleX, nLen)) + { + skip_char(rCandidate, sal_Unicode(' '), sal_Unicode(','), nPos, nLen); + SvgNumber aScaleY(aScaleX); + readNumberAndUnit(rCandidate, nPos, aScaleY, nLen); + skip_char(rCandidate, sal_Unicode(' '), sal_Unicode(')'), nPos, nLen); + skip_char(rCandidate, sal_Unicode(' '), sal_Unicode(','), nPos, nLen); + + aMatrix = aMatrix * basegfx::tools::createScaleB2DHomMatrix( + aScaleX.solve(rInfoProvider), + aScaleY.solve(rInfoProvider)); + } + } + else if(rCandidate.match(aStrSkewX, nPos)) + { + // skewx element + nPos += aStrSkewX.getLength(); + skip_char(rCandidate, sal_Unicode(' '), sal_Unicode('('), nPos, nLen); + double fSkewX(0.0); + + if(readAngle(rCandidate, nPos, fSkewX, nLen)) + { + skip_char(rCandidate, sal_Unicode(' '), sal_Unicode(')'), nPos, nLen); + skip_char(rCandidate, sal_Unicode(' '), sal_Unicode(','), nPos, nLen); + + aMatrix = aMatrix * basegfx::tools::createShearXB2DHomMatrix(tan(fSkewX)); + } + } + else if(rCandidate.match(aStrSkewY, nPos)) + { + // skewy element + nPos += aStrSkewY.getLength(); + skip_char(rCandidate, sal_Unicode(' '), sal_Unicode('('), nPos, nLen); + double fSkewY(0.0); + + if(readAngle(rCandidate, nPos, fSkewY, nLen)) + { + skip_char(rCandidate, sal_Unicode(' '), sal_Unicode(')'), nPos, nLen); + skip_char(rCandidate, sal_Unicode(' '), sal_Unicode(','), nPos, nLen); + + aMatrix = aMatrix * basegfx::tools::createShearYB2DHomMatrix(tan(fSkewY)); + } + } + break; + } + case sal_Unicode('r') : + { + if(rCandidate.match(aStrRotate, nPos)) + { + // rotate element + nPos += aStrRotate.getLength(); + skip_char(rCandidate, sal_Unicode(' '), sal_Unicode('('), nPos, nLen); + double fAngle(0.0); + + if(readAngle(rCandidate, nPos, fAngle, nLen)) + { + skip_char(rCandidate, sal_Unicode(' '), sal_Unicode(','), nPos, nLen); + SvgNumber aX; + readNumberAndUnit(rCandidate, nPos, aX, nLen); + skip_char(rCandidate, sal_Unicode(' '), sal_Unicode(','), nPos, nLen); + SvgNumber aY; + readNumberAndUnit(rCandidate, nPos, aY, nLen); + skip_char(rCandidate, sal_Unicode(' '), sal_Unicode(')'), nPos, nLen); + skip_char(rCandidate, sal_Unicode(' '), sal_Unicode(','), nPos, nLen); + + const double fX(aX.isSet() ? aX.solve(rInfoProvider, xcoordinate) : 0.0); + const double fY(aY.isSet() ? aY.solve(rInfoProvider, ycoordinate) : 0.0); + + if(!basegfx::fTools::equalZero(fX) || !basegfx::fTools::equalZero(fY)) + { + // rotate around point + aMatrix = aMatrix * basegfx::tools::createRotateAroundPoint(fX, fY, fAngle); + } + else + { + // rotate + aMatrix = aMatrix * basegfx::tools::createRotateB2DHomMatrix(fAngle); + } + } + } + break; + } + } + + if(nInitPos == nPos) + { + OSL_ENSURE(false, "Could not interpret on current position (!)"); + nPos++; + } + } + } + + return aMatrix; + } + + bool readSingleNumber(const rtl::OUString& rCandidate, SvgNumber& aNum) + { + const sal_Int32 nLen(rCandidate.getLength()); + sal_Int32 nPos(0); + + return readNumberAndUnit(rCandidate, nPos, aNum, nLen); + } + + bool readLocalUrl(const rtl::OUString& rCandidate, rtl::OUString& rURL) + { + static rtl::OUString aStrUrl(rtl::OUString::createFromAscii("url")); + + if(rCandidate.match(aStrUrl, 0)) + { + const sal_Int32 nLen(rCandidate.getLength()); + sal_Int32 nPos(aStrUrl.getLength()); + + skip_char(rCandidate, sal_Unicode('('), sal_Unicode('#'), nPos, nLen); + rtl::OUStringBuffer aTokenValue; + copyToLimiter(rCandidate, sal_Unicode(')'), nPos, aTokenValue, nLen); + rURL = aTokenValue.makeStringAndClear(); + + return true; + } + + return false; + } + + bool readSvgPaint(const rtl::OUString& rCandidate, SvgPaint& rSvgPaint, rtl::OUString& rURL) + { + const sal_Int32 nLen(rCandidate.getLength()); + + if(nLen) + { + basegfx::BColor aColor; + + if(read_color(rCandidate, aColor)) + { + rSvgPaint = SvgPaint(aColor, true, true); + return true; + } + else + { + static rtl::OUString aStrNone(rtl::OUString::createFromAscii("none")); + static rtl::OUString aStrCurrentColor(rtl::OUString::createFromAscii("currentColor")); + + if(rCandidate.match(aStrNone, 0)) + { + rSvgPaint = SvgPaint(aColor, true, false, false); + return true; + } + else if(readLocalUrl(rCandidate, rURL)) + { + /// Url is copied to rURL, but needs to be solved outside this helper + return false; + } + else if(rCandidate.match(aStrCurrentColor, 0)) + { + rSvgPaint = SvgPaint(aColor, true, true, true); + return true; + } + } + } + + return false; + } + + bool readSvgNumberVector(const rtl::OUString& rCandidate, SvgNumberVector& rSvgNumberVector) + { + const sal_Int32 nLen(rCandidate.getLength()); + rSvgNumberVector.clear(); + + if(nLen) + { + sal_Int32 nPos(0); + SvgNumber aNum; + skip_char(rCandidate, sal_Unicode(' '), sal_Unicode(','), nPos, nLen); + + while(readNumberAndUnit(rCandidate, nPos, aNum, nLen)) + { + rSvgNumberVector.push_back(aNum); + skip_char(rCandidate, sal_Unicode(' '), sal_Unicode(','), nPos, nLen); + } + + return !rSvgNumberVector.empty(); + } + + return false; + } + + SvgAspectRatio readSvgAspectRatio(const rtl::OUString& rCandidate) + { + const sal_Int32 nLen(rCandidate.getLength()); + + if(nLen) + { + sal_Int32 nPos(0); + SvgAlign aSvgAlign(Align_xMidYMid); + bool bDefer(false); + bool bMeetOrSlice(true); + bool bChanged(false); + + while(nPos < nLen) + { + const sal_Int32 nInitPos(nPos); + skip_char(rCandidate, sal_Unicode(' '), nPos, nLen); + rtl::OUStringBuffer aTokenName; + copyString(rCandidate, nPos, aTokenName, nLen); + + if(aTokenName.getLength()) + { + switch(StrToSVGToken(aTokenName.makeStringAndClear())) + { + case SVGTokenDefer: + { + bDefer = true; + bChanged = true; + break; + } + case SVGTokenNone: + { + aSvgAlign = Align_none; + bChanged = true; + break; + } + case SVGTokenXMinYMin: + { + aSvgAlign = Align_xMinYMin; + bChanged = true; + break; + } + case SVGTokenXMidYMin: + { + aSvgAlign = Align_xMidYMin; + bChanged = true; + break; + } + case SVGTokenXMaxYMin: + { + aSvgAlign = Align_xMaxYMin; + bChanged = true; + break; + } + case SVGTokenXMinYMid: + { + aSvgAlign = Align_xMinYMid; + bChanged = true; + break; + } + case SVGTokenXMidYMid: + { + aSvgAlign = Align_xMidYMid; + bChanged = true; + break; + } + case SVGTokenXMaxYMid: + { + aSvgAlign = Align_xMaxYMid; + bChanged = true; + break; + } + case SVGTokenXMinYMax: + { + aSvgAlign = Align_xMinYMax; + bChanged = true; + break; + } + case SVGTokenXMidYMax: + { + aSvgAlign = Align_xMidYMax; + bChanged = true; + break; + } + case SVGTokenXMaxYMax: + { + aSvgAlign = Align_xMaxYMax; + bChanged = true; + break; + } + case SVGTokenMeet: + { + bMeetOrSlice = true; + bChanged = true; + break; + } + case SVGTokenSlice: + { + bMeetOrSlice = false; + bChanged = true; + break; + } + default: + { + break; + } + } + } + + if(nInitPos == nPos) + { + OSL_ENSURE(false, "Could not interpret on current position (!)"); + nPos++; + } + } + + if(bChanged) + { + return SvgAspectRatio(aSvgAlign, bDefer, bMeetOrSlice); + } + } + + return SvgAspectRatio(); + } + + bool readSvgStringVector(const rtl::OUString& rCandidate, SvgStringVector& rSvgStringVector) + { + rSvgStringVector.clear(); + const sal_Int32 nLen(rCandidate.getLength()); + + if(nLen) + { + sal_Int32 nPos(0); + rtl::OUStringBuffer aTokenValue; + skip_char(rCandidate, sal_Unicode(' '), sal_Unicode(','), nPos, nLen); + + while(nPos < nLen) + { + copyToLimiter(rCandidate, sal_Unicode(','), nPos, aTokenValue, nLen); + skip_char(rCandidate, sal_Unicode(','), sal_Unicode(' '), nPos, nLen); + const rtl::OUString aString = aTokenValue.makeStringAndClear(); + + if(aString.getLength()) + { + rSvgStringVector.push_back(aString); + } + } + } + + return !rSvgStringVector.empty(); + } + + void readImageLink(const rtl::OUString& rCandidate, rtl::OUString& rXLink, rtl::OUString& rUrl, rtl::OUString& rMimeType, rtl::OUString& rData) + { + rXLink = rUrl = rMimeType = rData = rtl::OUString(); + + if(sal_Unicode('#') == rCandidate[0]) + { + // local link + rXLink = rCandidate.copy(1); + } + else + { + static rtl::OUString aStrData(rtl::OUString::createFromAscii("data:")); + + if(rCandidate.match(aStrData, 0)) + { + // embedded data + sal_Int32 nPos(aStrData.getLength()); + sal_Int32 nLen(rCandidate.getLength()); + rtl::OUStringBuffer aBuffer; + + // read mime type + skip_char(rCandidate, sal_Unicode(' '), nPos, nLen); + copyToLimiter(rCandidate, sal_Unicode(';'), nPos, aBuffer, nLen); + skip_char(rCandidate, sal_Unicode(' '), sal_Unicode(';'), nPos, nLen); + rMimeType = aBuffer.makeStringAndClear(); + + if(rMimeType.getLength() && nPos < nLen) + { + static rtl::OUString aStrImage(rtl::OUString::createFromAscii("image")); + + if(rMimeType.match(aStrImage, 0)) + { + // image data + rtl::OUString aData(rCandidate.copy(nPos)); + static rtl::OUString aStrBase64(rtl::OUString::createFromAscii("base64")); + + if(aData.match(aStrBase64, 0)) + { + // base64 encoded + nPos = aStrBase64.getLength(); + nLen = aData.getLength(); + + skip_char(aData, sal_Unicode(' '), sal_Unicode(','), nPos, nLen); + + if(nPos < nLen) + { + rData = aData.copy(nPos); + } + } + } + } + } + else + { + // Url (path and filename) + rUrl = rCandidate; + } + } + } + + rtl::OUString convert(const rtl::OUString& rCandidate, const sal_Unicode& rPattern, const sal_Unicode& rNew, bool bRemove) + { + const sal_Int32 nLen(rCandidate.getLength()); + + if(nLen) + { + sal_Int32 nPos(0); + rtl::OUStringBuffer aBuffer; + bool bChanged(false); + + while(nPos < nLen) + { + const sal_Unicode aChar(rCandidate[nPos]); + + if(rPattern == aChar) + { + bChanged = true; + + if(!bRemove) + { + aBuffer.append(rNew); + } + } + else + { + aBuffer.append(aChar); + } + + nPos++; + } + + if(bChanged) + { + return aBuffer.makeStringAndClear(); + } + } + + return rCandidate; + } + + rtl::OUString consolidateContiguosSpace(const rtl::OUString& rCandidate) + { + const sal_Int32 nLen(rCandidate.getLength()); + + if(nLen) + { + sal_Int32 nPos(0); + rtl::OUStringBuffer aBuffer; + bool bInsideSpace(false); + const sal_Unicode aSpace(' '); + + while(nPos < nLen) + { + const sal_Unicode aChar(rCandidate[nPos]); + + if(aSpace == aChar) + { + bInsideSpace = true; + } + else + { + if(bInsideSpace) + { + bInsideSpace = false; + aBuffer.append(aSpace); + } + + aBuffer.append(aChar); + } + + nPos++; + } + + if(bInsideSpace) + { + aBuffer.append(aSpace); + } + + if(aBuffer.getLength() != nLen) + { + return aBuffer.makeStringAndClear(); + } + } + + return rCandidate; + } + + rtl::OUString whiteSpaceHandlingDefault(const rtl::OUString& rCandidate) + { + const sal_Unicode aNewline('\n'); + const sal_Unicode aTab('\t'); + const sal_Unicode aSpace(' '); + + // remove all newline characters + rtl::OUString aRetval(convert(rCandidate, aNewline, aNewline, true)); + + // convert tab to space + aRetval = convert(aRetval, aTab, aSpace, false); + + // strip of all leading and trailing spaces + aRetval = aRetval.trim(); + + // consolidate contiguos space + aRetval = consolidateContiguosSpace(aRetval); + + return aRetval; + } + + rtl::OUString whiteSpaceHandlingPreserve(const rtl::OUString& rCandidate) + { + const sal_Unicode aNewline('\n'); + const sal_Unicode aTab('\t'); + const sal_Unicode aSpace(' '); + + // convert newline to space + rtl::OUString aRetval(convert(rCandidate, aNewline, aSpace, false)); + + // convert tab to space + aRetval = convert(rCandidate, aTab, aSpace, false); + + return rCandidate; + } + + ::std::vector< double > solveSvgNumberVector(const SvgNumberVector& rInput, const InfoProvider& rInfoProvider, NumberType aNumberType) + { + ::std::vector< double > aRetval; + + if(!rInput.empty()) + { + const double nCount(rInput.size()); + aRetval.reserve(nCount); + + for(sal_uInt32 a(0); a < nCount; a++) + { + aRetval.push_back(rInput[a].solve(rInfoProvider, aNumberType)); + } + } + + return aRetval; + } + + } // end of namespace svgreader +} // end of namespace svgio + +////////////////////////////////////////////////////////////////////////////// +// eof + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svgio/source/svgreader/svgtrefnode.cxx b/svgio/source/svgreader/svgtrefnode.cxx new file mode 100644 index 000000000000..7e4586345908 --- /dev/null +++ b/svgio/source/svgreader/svgtrefnode.cxx @@ -0,0 +1,91 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <svgio/svgreader/svgtrefnode.hxx> +#include <svgio/svgreader/svgdocument.hxx> + +////////////////////////////////////////////////////////////////////////////// + +namespace svgio +{ + namespace svgreader + { + SvgTrefNode::SvgTrefNode( + SvgDocument& rDocument, + SvgNode* pParent) + : SvgNode(SVGTokenTref, rDocument, pParent), + maSvgStyleAttributes(*this), + maXLink() + { + } + + SvgTrefNode::~SvgTrefNode() + { + } + + const SvgStyleAttributes* SvgTrefNode::getSvgStyleAttributes() const + { + return &maSvgStyleAttributes; + } + + void SvgTrefNode::parseAttribute(const rtl::OUString& rTokenName, SVGToken aSVGToken, const rtl::OUString& aContent) + { + // call parent + SvgNode::parseAttribute(rTokenName, aSVGToken, aContent); + + // read style attributes + maSvgStyleAttributes.parseStyleAttribute(rTokenName, aSVGToken, aContent); + + // parse own + switch(aSVGToken) + { + case SVGTokenStyle: + { + maSvgStyleAttributes.readStyle(aContent); + break; + } + case SVGTokenXlinkHref: + { + const sal_Int32 nLen(aContent.getLength()); + + if(nLen && sal_Unicode('#') == aContent[0]) + { + maXLink = aContent.copy(1); + } + break; + } + default: + { + break; + } + } + } + + const SvgTextNode* SvgTrefNode::getReferencedSvgTextNode() const + { + return dynamic_cast< const SvgTextNode* >(getDocument().findSvgNodeById(maXLink)); + } + + } // end of namespace svgreader +} // end of namespace svgio + +////////////////////////////////////////////////////////////////////////////// +// eof + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svgio/source/svgreader/svgtspannode.cxx b/svgio/source/svgreader/svgtspannode.cxx new file mode 100644 index 000000000000..177830c770f9 --- /dev/null +++ b/svgio/source/svgreader/svgtspannode.cxx @@ -0,0 +1,78 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <svgio/svgreader/svgtspannode.hxx> + +////////////////////////////////////////////////////////////////////////////// + +namespace svgio +{ + namespace svgreader + { + SvgTspanNode::SvgTspanNode( + SvgDocument& rDocument, + SvgNode* pParent) + : SvgNode(SVGTokenTspan, rDocument, pParent), + maSvgStyleAttributes(*this), + maSvgTextPositions() + { + } + + SvgTspanNode::~SvgTspanNode() + { + } + + const SvgStyleAttributes* SvgTspanNode::getSvgStyleAttributes() const + { + return &maSvgStyleAttributes; + } + + void SvgTspanNode::parseAttribute(const rtl::OUString& rTokenName, SVGToken aSVGToken, const rtl::OUString& aContent) + { + // call parent + SvgNode::parseAttribute(rTokenName, aSVGToken, aContent); + + // read style attributes + maSvgStyleAttributes.parseStyleAttribute(rTokenName, aSVGToken, aContent); + + // read text position attributes + maSvgTextPositions.parseTextPositionAttributes(rTokenName, aSVGToken, aContent); + + // parse own + switch(aSVGToken) + { + case SVGTokenStyle: + { + maSvgStyleAttributes.readStyle(aContent); + break; + } + default: + { + break; + } + } + } + + } // end of namespace svgreader +} // end of namespace svgio + +////////////////////////////////////////////////////////////////////////////// +// eof + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svgio/source/svgreader/svgusenode.cxx b/svgio/source/svgreader/svgusenode.cxx new file mode 100644 index 000000000000..d978f39ab352 --- /dev/null +++ b/svgio/source/svgreader/svgusenode.cxx @@ -0,0 +1,201 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <svgio/svgreader/svgusenode.hxx> +#include <drawinglayer/primitive2d/transformprimitive2d.hxx> +#include <svgio/svgreader/svgdocument.hxx> + +////////////////////////////////////////////////////////////////////////////// + +namespace svgio +{ + namespace svgreader + { + SvgUseNode::SvgUseNode( + SvgDocument& rDocument, + SvgNode* pParent) + : SvgNode(SVGTokenG, rDocument, pParent), + maSvgStyleAttributes(*this), + mpaTransform(0), + maX(), + maY(), + maWidth(), + maHeight(), + maXLink() + { + } + + SvgUseNode::~SvgUseNode() + { + if(mpaTransform) delete mpaTransform; + } + + const SvgStyleAttributes* SvgUseNode::getSvgStyleAttributes() const + { + static rtl::OUString aClassStr(rtl::OUString::createFromAscii("use")); + maSvgStyleAttributes.checkForCssStyle(aClassStr); + + return &maSvgStyleAttributes; + } + + void SvgUseNode::parseAttribute(const rtl::OUString& rTokenName, SVGToken aSVGToken, const rtl::OUString& aContent) + { + // call parent + SvgNode::parseAttribute(rTokenName, aSVGToken, aContent); + + // read style attributes + maSvgStyleAttributes.parseStyleAttribute(rTokenName, aSVGToken, aContent); + + // parse own + switch(aSVGToken) + { + case SVGTokenStyle: + { + maSvgStyleAttributes.readStyle(aContent); + break; + } + case SVGTokenTransform: + { + const basegfx::B2DHomMatrix aMatrix(readTransform(aContent, *this)); + + if(!aMatrix.isIdentity()) + { + setTransform(&aMatrix); + } + break; + } + case SVGTokenX: + { + SvgNumber aNum; + + if(readSingleNumber(aContent, aNum)) + { + setX(aNum); + } + break; + } + case SVGTokenY: + { + SvgNumber aNum; + + if(readSingleNumber(aContent, aNum)) + { + setY(aNum); + } + break; + } + case SVGTokenWidth: + { + SvgNumber aNum; + + if(readSingleNumber(aContent, aNum)) + { + if(aNum.isPositive()) + { + setWidth(aNum); + } + } + break; + } + case SVGTokenHeight: + { + SvgNumber aNum; + + if(readSingleNumber(aContent, aNum)) + { + if(aNum.isPositive()) + { + setHeight(aNum); + } + } + } + case SVGTokenXlinkHref: + { + const sal_Int32 nLen(aContent.getLength()); + + if(nLen && sal_Unicode('#') == aContent[0]) + { + maXLink = aContent.copy(1); + } + break; + } + default: + { + break; + } + } + } + + void SvgUseNode::decomposeSvgNode(drawinglayer::primitive2d::Primitive2DSequence& rTarget, bool /*bReferenced*/) const + { + // try to access link to content + const SvgNode* mpXLink = getDocument().findSvgNodeById(maXLink); + + if(mpXLink) + { + // decompose childs + drawinglayer::primitive2d::Primitive2DSequence aNewTarget; + + // todo: in case mpXLink is a SVGTokenSvg or SVGTokenSymbol the + // SVG docs want the getWidth() and getHeight() from this node + // to be valid for the subtree. + const_cast< SvgNode* >(mpXLink)->setAlternativeParent(this); + mpXLink->decomposeSvgNode(aNewTarget, true); + const_cast< SvgNode* >(mpXLink)->setAlternativeParent(0); + + if(aNewTarget.hasElements()) + { + basegfx::B2DHomMatrix aTransform; + + if(getX().isSet() || getY().isSet()) + { + aTransform.translate( + getX().solve(*this, xcoordinate), + getY().solve(*this, ycoordinate)); + } + + if(getTransform()) + { + aTransform = *getTransform() * aTransform; + } + + if(!aTransform.isIdentity()) + { + const drawinglayer::primitive2d::Primitive2DReference xRef( + new drawinglayer::primitive2d::TransformPrimitive2D( + aTransform, + aNewTarget)); + + drawinglayer::primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(rTarget, xRef); + } + else + { + drawinglayer::primitive2d::appendPrimitive2DSequenceToPrimitive2DSequence(rTarget, aNewTarget); + } + } + } + } + + } // end of namespace svgreader +} // end of namespace svgio + +////////////////////////////////////////////////////////////////////////////// +// eof + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svgio/source/svguno/svguno.cxx b/svgio/source/svguno/svguno.cxx new file mode 100644 index 000000000000..41cc46168b82 --- /dev/null +++ b/svgio/source/svguno/svguno.cxx @@ -0,0 +1,92 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <svgio/svgiodllapi.h> +#include <com/sun/star/uno/Reference.h> +#include <com/sun/star/uno/RuntimeException.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/lang/XComponent.hpp> +#include <com/sun/star/registry/XRegistryKey.hpp> +#include <com/sun/star/lang/XComponent.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/lang/XSingleServiceFactory.hpp> +#include <uno/environment.h> +#include <cppuhelper/factory.hxx> + +////////////////////////////////////////////////////////////////////////////// + +using namespace ::com::sun::star; + +////////////////////////////////////////////////////////////////////////////// +// predefines + +namespace svgio +{ + namespace svgreader + { + extern uno::Sequence< rtl::OUString > SAL_CALL XSvgParser_getSupportedServiceNames(); + extern rtl::OUString SAL_CALL XSvgParser_getImplementationName(); + extern uno::Reference< uno::XInterface > SAL_CALL XSvgParser_createInstance( const uno::Reference< lang::XMultiServiceFactory > & ); + } // end of namespace svgreader +} // end of namespace svgio + +////////////////////////////////////////////////////////////////////////////// +// component_getImplementationEnvironment + +extern "C" +{ + SVGIO_DLLPUBLIC void SAL_CALL component_getImplementationEnvironment( const sal_Char ** ppEnvTypeName, uno_Environment ** /* ppEnv */ ) + { + *ppEnvTypeName = CPPU_CURRENT_LANGUAGE_BINDING_NAME; + } +} + +////////////////////////////////////////////////////////////////////////////// +// component_getFactory + +extern "C" +{ + SVGIO_DLLPUBLIC void* SAL_CALL component_getFactory( const sal_Char* pImplName, void* pServiceManager, void* /* pRegistryKey */ ) + { + uno::Reference< lang::XSingleServiceFactory > xFactory; + void* pRet = 0; + + if(svgio::svgreader::XSvgParser_getImplementationName().equalsAscii(pImplName)) + { + xFactory = ::cppu::createSingleFactory( + reinterpret_cast< lang::XMultiServiceFactory * >(pServiceManager), + svgio::svgreader::XSvgParser_getImplementationName(), + svgio::svgreader::XSvgParser_createInstance, + svgio::svgreader::XSvgParser_getSupportedServiceNames()); + } + + if(xFactory.is()) + { + xFactory->acquire(); + pRet = xFactory.get(); + } + + return pRet; + } +} + +////////////////////////////////////////////////////////////////////////////// +// eof + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svgio/source/svguno/xsvgparser.cxx b/svgio/source/svguno/xsvgparser.cxx new file mode 100644 index 000000000000..d08080f8fb13 --- /dev/null +++ b/svgio/source/svguno/xsvgparser.cxx @@ -0,0 +1,191 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <com/sun/star/graphic/XSvgParser.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <cppuhelper/implbase2.hxx> +#include <svgio/svgreader/svgdocumenthandler.hxx> +#include <com/sun/star/xml/sax/XParser.hpp> +#include <com/sun/star/xml/sax/InputSource.hpp> +#include <comphelper/processfactory.hxx> +#include <drawinglayer/geometry/viewinformation2d.hxx> + +////////////////////////////////////////////////////////////////////////////// + +using namespace ::com::sun::star; + +////////////////////////////////////////////////////////////////////////////// + +namespace svgio +{ + namespace svgreader + { + class XSvgParser : public ::cppu::WeakAggImplHelper2< graphic::XSvgParser, lang::XServiceInfo > + { + private: + XSvgParser(const XSvgParser&); + XSvgParser& operator=(const XSvgParser&); + + protected: + public: + XSvgParser(); + virtual ~XSvgParser(); + + // XSvgParser + virtual uno::Sequence< uno::Reference< ::graphic::XPrimitive2D > > SAL_CALL getDecomposition( + const uno::Reference< ::io::XInputStream >& xSVGStream, + const ::rtl::OUString& aAbsolutePath) throw (uno::RuntimeException); + + // XServiceInfo + virtual rtl::OUString SAL_CALL getImplementationName() throw(uno::RuntimeException); + virtual ::sal_Bool SAL_CALL supportsService(const rtl::OUString&) throw(uno::RuntimeException); + virtual uno::Sequence< rtl::OUString > SAL_CALL getSupportedServiceNames() throw(uno::RuntimeException); + }; + } // end of namespace svgreader +} // end of namespace svgio + +////////////////////////////////////////////////////////////////////////////// +// uno functions + +namespace svgio +{ + namespace svgreader + { + uno::Sequence< rtl::OUString > XSvgParser_getSupportedServiceNames() + { + static rtl::OUString aServiceName(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.graphic.SvgTools" ) ); + static uno::Sequence< rtl::OUString > aServiceNames( &aServiceName, 1 ); + + return( aServiceNames ); + } + + rtl::OUString XSvgParser_getImplementationName() + { + return rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "svgio::svgreader::XSvgParser" ) ); + } + + uno::Reference< uno::XInterface > SAL_CALL XSvgParser_createInstance(const uno::Reference< lang::XMultiServiceFactory >&) + { + return static_cast< ::cppu::OWeakObject* >(new XSvgParser); + } + } // end of namespace svgreader +} // end of namespace svgio + +////////////////////////////////////////////////////////////////////////////// + +namespace svgio +{ + namespace svgreader + { + XSvgParser::XSvgParser() + { + } + + XSvgParser::~XSvgParser() + { + } + + uno::Sequence< uno::Reference< ::graphic::XPrimitive2D > > XSvgParser::getDecomposition( + const uno::Reference< ::io::XInputStream >& xSVGStream, + const ::rtl::OUString& aAbsolutePath ) throw (uno::RuntimeException) + { + drawinglayer::primitive2d::Primitive2DSequence aRetval; + + if(xSVGStream.is()) + { + // local document handler + SvgDocHdl* pSvgDocHdl = new SvgDocHdl(aAbsolutePath); + uno::Reference< xml::sax::XDocumentHandler > xSvgDocHdl(pSvgDocHdl); + + try + { + // prepare ParserInputSrouce + xml::sax::InputSource myInputSource; + myInputSource.aInputStream = xSVGStream; + + // get parser + uno::Reference< xml::sax::XParser > xParser( + comphelper::getProcessServiceFactory()->createInstance( + rtl::OUString::createFromAscii("com.sun.star.xml.sax.Parser") ), + uno::UNO_QUERY_THROW ); + + // connect parser and filter + xParser->setDocumentHandler(xSvgDocHdl); + + // finally, parse the stream to a hierarchy of + // SVGGraphicPrimitive2D which will be embedded to the + // primitive sequence. Their decompositions will in the + // end create local low-level primitives, thus SVG will + // be processable from all our processors + xParser->parseStream(myInputSource); + } + catch(uno::Exception&) + { + OSL_ENSURE(false, "Parse error (!)"); + } + + // decompose to primitives + const SvgNodeVector& rResults = pSvgDocHdl->getSvgDocument().getSvgNodeVector(); + const sal_uInt32 nCount(rResults.size()); + + for(sal_uInt32 a(0); a < nCount; a++) + { + rResults[a]->decomposeSvgNode(aRetval, false); + } + } + else + { + OSL_ENSURE(false, "Invalid stream (!)"); + } + + return aRetval; + } + + rtl::OUString SAL_CALL XSvgParser::getImplementationName() throw(uno::RuntimeException) + { + return(XSvgParser_getImplementationName()); + } + + sal_Bool SAL_CALL XSvgParser::supportsService(const rtl::OUString& rServiceName) throw(uno::RuntimeException) + { + const uno::Sequence< rtl::OUString > aServices(XSvgParser_getSupportedServiceNames()); + + for(sal_Int32 nService(0); nService < aServices.getLength(); nService++) + { + if(rServiceName == aServices[nService]) + { + return sal_True; + } + } + + return sal_False; + } + + uno::Sequence< rtl::OUString > SAL_CALL XSvgParser::getSupportedServiceNames() throw(uno::RuntimeException) + { + return XSvgParser_getSupportedServiceNames(); + } + + } // end of namespace svgreader +} // end of namespace svgio + +////////////////////////////////////////////////////////////////////////////// +// eof + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svgio/svgio.component b/svgio/svgio.component new file mode 100644 index 000000000000..ddba96500dec --- /dev/null +++ b/svgio/svgio.component @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + --> + +<component loader="com.sun.star.loader.SharedLibrary" + xmlns="http://openoffice.org/2010/uno-components"> + <implementation name="svgio::svgreader::XSvgParser"> + <service name="com.sun.star.graphic.SvgTools"/> + </implementation> +</component> |