diff --git a/.checkstyle b/.checkstyle
new file mode 100644
index 0000000..34ed486
--- /dev/null
+++ b/.checkstyle
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/.classpath b/.classpath
new file mode 100644
index 0000000..d43dd0c
--- /dev/null
+++ b/.classpath
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..d075be7
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,17 @@
+/bin/
+/Operator/
+/DrawerProperties/
+*.pdfd
+*.dbc
+SchedulerConfig.txt
+scenicView.properties
+ScenariumConfig.txt
+*.class
+*~
+*.bck
+build.number
+/extern/
+/out/
+/.settings/
+/junit/
+/target/
diff --git a/.project b/.project
new file mode 100644
index 0000000..e14ad1b
--- /dev/null
+++ b/.project
@@ -0,0 +1,24 @@
+
+
+ atriasoft-esvg
+
+
+ atriasoft-esvg
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+ net.sf.eclipsecs.core.CheckstyleBuilder
+
+
+
+
+
+ org.eclipse.jdt.core.javanature
+ net.sf.eclipsecs.core.CheckstyleNature
+
+
diff --git a/CheckStyle.xml b/CheckStyle.xml
new file mode 100755
index 0000000..d68aedd
--- /dev/null
+++ b/CheckStyle.xml
@@ -0,0 +1,66 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/CleanUp.xml b/CleanUp.xml
new file mode 100644
index 0000000..6cf4cba
--- /dev/null
+++ b/CleanUp.xml
@@ -0,0 +1,106 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Formatter.xml b/Formatter.xml
new file mode 100644
index 0000000..14a5d6c
--- /dev/null
+++ b/Formatter.xml
@@ -0,0 +1,390 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..a612ad9
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,373 @@
+Mozilla Public License Version 2.0
+==================================
+
+1. Definitions
+--------------
+
+1.1. "Contributor"
+ means each individual or legal entity that creates, contributes to
+ the creation of, or owns Covered Software.
+
+1.2. "Contributor Version"
+ means the combination of the Contributions of others (if any) used
+ by a Contributor and that particular Contributor's Contribution.
+
+1.3. "Contribution"
+ means Covered Software of a particular Contributor.
+
+1.4. "Covered Software"
+ means Source Code Form to which the initial Contributor has attached
+ the notice in Exhibit A, the Executable Form of such Source Code
+ Form, and Modifications of such Source Code Form, in each case
+ including portions thereof.
+
+1.5. "Incompatible With Secondary Licenses"
+ means
+
+ (a) that the initial Contributor has attached the notice described
+ in Exhibit B to the Covered Software; or
+
+ (b) that the Covered Software was made available under the terms of
+ version 1.1 or earlier of the License, but not also under the
+ terms of a Secondary License.
+
+1.6. "Executable Form"
+ means any form of the work other than Source Code Form.
+
+1.7. "Larger Work"
+ means a work that combines Covered Software with other material, in
+ a separate file or files, that is not Covered Software.
+
+1.8. "License"
+ means this document.
+
+1.9. "Licensable"
+ means having the right to grant, to the maximum extent possible,
+ whether at the time of the initial grant or subsequently, any and
+ all of the rights conveyed by this License.
+
+1.10. "Modifications"
+ means any of the following:
+
+ (a) any file in Source Code Form that results from an addition to,
+ deletion from, or modification of the contents of Covered
+ Software; or
+
+ (b) any new file in Source Code Form that contains any Covered
+ Software.
+
+1.11. "Patent Claims" of a Contributor
+ means any patent claim(s), including without limitation, method,
+ process, and apparatus claims, in any patent Licensable by such
+ Contributor that would be infringed, but for the grant of the
+ License, by the making, using, selling, offering for sale, having
+ made, import, or transfer of either its Contributions or its
+ Contributor Version.
+
+1.12. "Secondary License"
+ means either the GNU General Public License, Version 2.0, the GNU
+ Lesser General Public License, Version 2.1, the GNU Affero General
+ Public License, Version 3.0, or any later versions of those
+ licenses.
+
+1.13. "Source Code Form"
+ means the form of the work preferred for making modifications.
+
+1.14. "You" (or "Your")
+ means an individual or a legal entity exercising rights under this
+ License. For legal entities, "You" includes any entity that
+ controls, is controlled by, or is under common control with You. For
+ purposes of this definition, "control" means (a) the power, direct
+ or indirect, to cause the direction or management of such entity,
+ whether by contract or otherwise, or (b) ownership of more than
+ fifty percent (50%) of the outstanding shares or beneficial
+ ownership of such entity.
+
+2. License Grants and Conditions
+--------------------------------
+
+2.1. Grants
+
+Each Contributor hereby grants You a world-wide, royalty-free,
+non-exclusive license:
+
+(a) under intellectual property rights (other than patent or trademark)
+ Licensable by such Contributor to use, reproduce, make available,
+ modify, display, perform, distribute, and otherwise exploit its
+ Contributions, either on an unmodified basis, with Modifications, or
+ as part of a Larger Work; and
+
+(b) under Patent Claims of such Contributor to make, use, sell, offer
+ for sale, have made, import, and otherwise transfer either its
+ Contributions or its Contributor Version.
+
+2.2. Effective Date
+
+The licenses granted in Section 2.1 with respect to any Contribution
+become effective for each Contribution on the date the Contributor first
+distributes such Contribution.
+
+2.3. Limitations on Grant Scope
+
+The licenses granted in this Section 2 are the only rights granted under
+this License. No additional rights or licenses will be implied from the
+distribution or licensing of Covered Software under this License.
+Notwithstanding Section 2.1(b) above, no patent license is granted by a
+Contributor:
+
+(a) for any code that a Contributor has removed from Covered Software;
+ or
+
+(b) for infringements caused by: (i) Your and any other third party's
+ modifications of Covered Software, or (ii) the combination of its
+ Contributions with other software (except as part of its Contributor
+ Version); or
+
+(c) under Patent Claims infringed by Covered Software in the absence of
+ its Contributions.
+
+This License does not grant any rights in the trademarks, service marks,
+or logos of any Contributor (except as may be necessary to comply with
+the notice requirements in Section 3.4).
+
+2.4. Subsequent Licenses
+
+No Contributor makes additional grants as a result of Your choice to
+distribute the Covered Software under a subsequent version of this
+License (see Section 10.2) or under the terms of a Secondary License (if
+permitted under the terms of Section 3.3).
+
+2.5. Representation
+
+Each Contributor represents that the Contributor believes its
+Contributions are its original creation(s) or it has sufficient rights
+to grant the rights to its Contributions conveyed by this License.
+
+2.6. Fair Use
+
+This License is not intended to limit any rights You have under
+applicable copyright doctrines of fair use, fair dealing, or other
+equivalents.
+
+2.7. Conditions
+
+Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
+in Section 2.1.
+
+3. Responsibilities
+-------------------
+
+3.1. Distribution of Source Form
+
+All distribution of Covered Software in Source Code Form, including any
+Modifications that You create or to which You contribute, must be under
+the terms of this License. You must inform recipients that the Source
+Code Form of the Covered Software is governed by the terms of this
+License, and how they can obtain a copy of this License. You may not
+attempt to alter or restrict the recipients' rights in the Source Code
+Form.
+
+3.2. Distribution of Executable Form
+
+If You distribute Covered Software in Executable Form then:
+
+(a) such Covered Software must also be made available in Source Code
+ Form, as described in Section 3.1, and You must inform recipients of
+ the Executable Form how they can obtain a copy of such Source Code
+ Form by reasonable means in a timely manner, at a charge no more
+ than the cost of distribution to the recipient; and
+
+(b) You may distribute such Executable Form under the terms of this
+ License, or sublicense it under different terms, provided that the
+ license for the Executable Form does not attempt to limit or alter
+ the recipients' rights in the Source Code Form under this License.
+
+3.3. Distribution of a Larger Work
+
+You may create and distribute a Larger Work under terms of Your choice,
+provided that You also comply with the requirements of this License for
+the Covered Software. If the Larger Work is a combination of Covered
+Software with a work governed by one or more Secondary Licenses, and the
+Covered Software is not Incompatible With Secondary Licenses, this
+License permits You to additionally distribute such Covered Software
+under the terms of such Secondary License(s), so that the recipient of
+the Larger Work may, at their option, further distribute the Covered
+Software under the terms of either this License or such Secondary
+License(s).
+
+3.4. Notices
+
+You may not remove or alter the substance of any license notices
+(including copyright notices, patent notices, disclaimers of warranty,
+or limitations of liability) contained within the Source Code Form of
+the Covered Software, except that You may alter any license notices to
+the extent required to remedy known factual inaccuracies.
+
+3.5. Application of Additional Terms
+
+You may choose to offer, and to charge a fee for, warranty, support,
+indemnity or liability obligations to one or more recipients of Covered
+Software. However, You may do so only on Your own behalf, and not on
+behalf of any Contributor. You must make it absolutely clear that any
+such warranty, support, indemnity, or liability obligation is offered by
+You alone, and You hereby agree to indemnify every Contributor for any
+liability incurred by such Contributor as a result of warranty, support,
+indemnity or liability terms You offer. You may include additional
+disclaimers of warranty and limitations of liability specific to any
+jurisdiction.
+
+4. Inability to Comply Due to Statute or Regulation
+---------------------------------------------------
+
+If it is impossible for You to comply with any of the terms of this
+License with respect to some or all of the Covered Software due to
+statute, judicial order, or regulation then You must: (a) comply with
+the terms of this License to the maximum extent possible; and (b)
+describe the limitations and the code they affect. Such description must
+be placed in a text file included with all distributions of the Covered
+Software under this License. Except to the extent prohibited by statute
+or regulation, such description must be sufficiently detailed for a
+recipient of ordinary skill to be able to understand it.
+
+5. Termination
+--------------
+
+5.1. The rights granted under this License will terminate automatically
+if You fail to comply with any of its terms. However, if You become
+compliant, then the rights granted under this License from a particular
+Contributor are reinstated (a) provisionally, unless and until such
+Contributor explicitly and finally terminates Your grants, and (b) on an
+ongoing basis, if such Contributor fails to notify You of the
+non-compliance by some reasonable means prior to 60 days after You have
+come back into compliance. Moreover, Your grants from a particular
+Contributor are reinstated on an ongoing basis if such Contributor
+notifies You of the non-compliance by some reasonable means, this is the
+first time You have received notice of non-compliance with this License
+from such Contributor, and You become compliant prior to 30 days after
+Your receipt of the notice.
+
+5.2. If You initiate litigation against any entity by asserting a patent
+infringement claim (excluding declaratory judgment actions,
+counter-claims, and cross-claims) alleging that a Contributor Version
+directly or indirectly infringes any patent, then the rights granted to
+You by any and all Contributors for the Covered Software under Section
+2.1 of this License shall terminate.
+
+5.3. In the event of termination under Sections 5.1 or 5.2 above, all
+end user license agreements (excluding distributors and resellers) which
+have been validly granted by You or Your distributors under this License
+prior to termination shall survive termination.
+
+************************************************************************
+* *
+* 6. Disclaimer of Warranty *
+* ------------------------- *
+* *
+* Covered Software is provided under this License on an "as is" *
+* basis, without warranty of any kind, either expressed, implied, or *
+* statutory, including, without limitation, warranties that the *
+* Covered Software is free of defects, merchantable, fit for a *
+* particular purpose or non-infringing. The entire risk as to the *
+* quality and performance of the Covered Software is with You. *
+* Should any Covered Software prove defective in any respect, You *
+* (not any Contributor) assume the cost of any necessary servicing, *
+* repair, or correction. This disclaimer of warranty constitutes an *
+* essential part of this License. No use of any Covered Software is *
+* authorized under this License except under this disclaimer. *
+* *
+************************************************************************
+
+************************************************************************
+* *
+* 7. Limitation of Liability *
+* -------------------------- *
+* *
+* Under no circumstances and under no legal theory, whether tort *
+* (including negligence), contract, or otherwise, shall any *
+* Contributor, or anyone who distributes Covered Software as *
+* permitted above, be liable to You for any direct, indirect, *
+* special, incidental, or consequential damages of any character *
+* including, without limitation, damages for lost profits, loss of *
+* goodwill, work stoppage, computer failure or malfunction, or any *
+* and all other commercial damages or losses, even if such party *
+* shall have been informed of the possibility of such damages. This *
+* limitation of liability shall not apply to liability for death or *
+* personal injury resulting from such party's negligence to the *
+* extent applicable law prohibits such limitation. Some *
+* jurisdictions do not allow the exclusion or limitation of *
+* incidental or consequential damages, so this exclusion and *
+* limitation may not apply to You. *
+* *
+************************************************************************
+
+8. Litigation
+-------------
+
+Any litigation relating to this License may be brought only in the
+courts of a jurisdiction where the defendant maintains its principal
+place of business and such litigation shall be governed by laws of that
+jurisdiction, without reference to its conflict-of-law provisions.
+Nothing in this Section shall prevent a party's ability to bring
+cross-claims or counter-claims.
+
+9. Miscellaneous
+----------------
+
+This License represents the complete agreement concerning the subject
+matter hereof. If any provision of this License is held to be
+unenforceable, such provision shall be reformed only to the extent
+necessary to make it enforceable. Any law or regulation which provides
+that the language of a contract shall be construed against the drafter
+shall not be used to construe this License against a Contributor.
+
+10. Versions of the License
+---------------------------
+
+10.1. New Versions
+
+Mozilla Foundation is the license steward. Except as provided in Section
+10.3, no one other than the license steward has the right to modify or
+publish new versions of this License. Each version will be given a
+distinguishing version number.
+
+10.2. Effect of New Versions
+
+You may distribute the Covered Software under the terms of the version
+of the License under which You originally received the Covered Software,
+or under the terms of any subsequent version published by the license
+steward.
+
+10.3. Modified Versions
+
+If you create software not governed by this License, and you want to
+create a new license for such software, you may create and use a
+modified version of this License if you rename the license and remove
+any references to the name of the license steward (except to note that
+such modified license differs from this License).
+
+10.4. Distributing Source Code Form that is Incompatible With Secondary
+Licenses
+
+If You choose to distribute Source Code Form that is Incompatible With
+Secondary Licenses under the terms of this version of the License, the
+notice described in Exhibit B of this License must be attached.
+
+Exhibit A - Source Code Form License Notice
+-------------------------------------------
+
+ 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/.
+
+If it is not possible or desirable to put the notice in a particular
+file, then You may include the notice in a location (such as a LICENSE
+file in a relevant directory) where a recipient would be likely to look
+for such a notice.
+
+You may add additional accurate notices of copyright ownership.
+
+Exhibit B - "Incompatible With Secondary Licenses" Notice
+---------------------------------------------------------
+
+ This Source Code Form is "Incompatible With Secondary Licenses", as
+ defined by the Mozilla Public License, v. 2.0.
diff --git a/src/module-info.java b/src/module-info.java
new file mode 100644
index 0000000..11c18b8
--- /dev/null
+++ b/src/module-info.java
@@ -0,0 +1,10 @@
+/** Basic module interface.
+ *
+ * @author Edouard DUPIN */
+
+open module org.atriasoft.esvg {
+ exports org.atriasoft.esvg;
+ exports org.atriasoft.esvg.render;
+
+ requires transitive io.scenarium.logger;
+}
diff --git a/src/org/atriasoft/esvg/Base.cpp b/src/org/atriasoft/esvg/Base.cpp
new file mode 100644
index 0000000..1932bee
--- /dev/null
+++ b/src/org/atriasoft/esvg/Base.cpp
@@ -0,0 +1,439 @@
+/** @file
+ * @author Edouard DUPIN
+ * @copyright 2011, Edouard DUPIN, all right reserved
+ * @license MPL v2.0 (see license file)
+ */
+
+
+#include
+#include
+#include
+
+const float esvg::kappa90(0.5522847493f);
+
+esvg::PaintState::PaintState() :
+ fill(etk::Pair, etk::String>(etk::color::black, "")),
+ stroke(etk::Pair, etk::String>(etk::color::none, "")),
+ strokeWidth(1.0f),
+ flagEvenOdd(false),
+ lineCap(esvg::cap_butt),
+ lineJoin(esvg::join_miter),
+ miterLimit(4.0f),
+ viewPort(vec2(0.0f,0.0f), vec2(0.0f,0.0f)),
+ opacity(1.0) {
+
+}
+
+void esvg::PaintState::clear() {
+ fill = etk::Pair, etk::String>(etk::color::black, "");
+ stroke = etk::Pair, etk::String>(etk::color::none, "");
+ strokeWidth = 1.0;
+ viewPort.first.setValue(0.0f,0.0f);
+ viewPort.first.setValue(0.0f,0.0f);
+ flagEvenOdd = false;
+ lineJoin = esvg::join_miter;
+ lineCap = esvg::cap_butt;
+ miterLimit = 4.0f;
+ opacity = 1.0;
+}
+
+
+esvg::Base::Base(PaintState _parentPaintState) {
+ // copy the parent painting properties ...
+ m_paint = _parentPaintState;
+}
+
+etk::String extractTransformData(const etk::String& _value, const etk::String& _base) {
+ size_t posStart = _value.find(_base);
+ if (posStart == etk::String::npos) {
+ // Not find element is a normal case ...
+ return "";
+ }
+ posStart += _base.size();
+ if (_value.size() < posStart+2) {
+ Log.error("Not enought spece in the String to have transform value for ' (' or '()' in '" << _value << "'");
+ return "";
+ }
+ if (_value[posStart] == '(') {
+ // normal SVG does not support this case ...
+ posStart++;
+ } else if ( _value[posStart] == ' '
+ && _value[posStart+1] == '(') {
+ posStart+=2;
+ } else {
+ Log.error("Can not find ' (' or '(' in '" << &_value[posStart] << "' for '" << _value << "'");
+ return "";
+ }
+ if (_value.size() < posStart+1) {
+ Log.error("Not enought spece in the String to have transform value for ')' in '" << _value << "'");
+ return "";
+ }
+ size_t posEnd = _value.find(')', posStart);
+ if (posEnd == etk::String::npos) {
+ Log.error("Missing element ')' in '" << _value << "' for " << _base);
+ return "";
+ }
+ Log.verbose("Find : '" << etk::String(_value.begin()+posStart, _value.begin()+posEnd) << "' for " << _base);
+ return etk::String(_value.begin()+posStart, _value.begin()+posEnd);
+}
+
+void esvg::Base::parseTransform(const exml::Element& _element) {
+ if (_element.exist() == false) {
+ return;
+ }
+ etk::String inputString = _element.attributes["transform"];
+ if (inputString.size() == 0) {
+ return;
+ }
+ Log.verbose("find transform : \"" << inputString << "\"");
+ for (size_t iii=0; iii esvg::Base::parseLength2(const etk::String& _dataInput) {
+ Log.verbose(" lenght : '" << _dataInput << "'");
+ float n = _dataInput.to();
+ etk::String unit;
+ for (size_t iii=0; iii<_dataInput.size(); ++iii) {
+ if( (_dataInput[iii]>='0' && _dataInput[iii]<='9')
+ || _dataInput[iii]=='+'
+ || _dataInput[iii]=='-'
+ || _dataInput[iii]=='.') {
+ continue;
+ }
+ unit = etk::String(_dataInput, iii);
+ break;
+ }
+ Log.verbose(" lenght : '" << n << "' => unit=" << unit);
+ // note : ";" is for the parsing of the style elements ...
+ if(unit.size() == 0) {
+ return etk::makePair(n, esvg::distance_pixel);
+ } else if (unit[0] == '%') { // xxx %
+ return etk::makePair(n, esvg::distance_pourcent);
+ } else if ( unit[0] == 'e'
+ && unit[1] == 'm') { // xxx em
+ return etk::makePair(n, esvg::distance_element);
+ } else if ( unit[0] == 'e'
+ && unit[1] == 'x') { // xxx ex
+ return etk::makePair(n, esvg::distance_ex);
+ } else if ( unit[0] == 'p'
+ && unit[1] == 'x') { // xxx px
+ return etk::makePair(n, esvg::distance_pixel);
+ } else if ( unit[0] == 'p'
+ && unit[1] == 't') { // xxx pt
+ return etk::makePair(n, esvg::distance_point);
+ } else if ( unit[0] == 'p'
+ && unit[1] == 'c') { // xxx pc
+ return etk::makePair(n, esvg::distance_pc);
+ } else if ( unit[0] == 'm'
+ && unit[1] == 'm') { // xxx mm
+ return etk::makePair(n, esvg::distance_millimeter);
+ } else if ( unit[0] == 'c'
+ && unit[1] == 'm') { // xxx cm
+ return etk::makePair(n, esvg::distance_centimeter);
+ } else if ( unit[0] == 'i'
+ && unit[1] == 'n') { // xxx in
+ return etk::makePair(n, esvg::distance_inch);
+ }
+ return etk::makePair(0.0f, esvg::distance_pixel);
+}
+
+
+float esvg::Base::parseLength(const etk::String& _dataInput) {
+ etk::Pair value = parseLength2(_dataInput);
+ Log.verbose(" lenght : '" << value.first << "' => unit=" << value.second);
+ float font_size = 20.0f;
+ switch (value.second) {
+ case esvg::distance_pourcent:
+ return value.first;// / 100.0 * m_paint.viewPort.x();
+ case esvg::distance_element:
+ return value.first * font_size;
+ case esvg::distance_ex:
+ return value.first / 2.0f * font_size;
+ case esvg::distance_pixel:
+ return value.first;
+ case esvg::distance_point:
+ return value.first * 1.25f;
+ case esvg::distance_pc:
+ return value.first * 15.0f;
+ case esvg::distance_millimeter:
+ return value.first * 3.543307f;
+ case esvg::distance_centimeter:
+ return value.first * 35.43307f;
+ case esvg::distance_inch:
+ return value.first * 90.0f;
+ }
+ return 0.0f;
+}
+
+void esvg::Base::parsePaintAttr(const exml::Element& _element) {
+ if (_element.exist() == false) {
+ return;
+ }
+ /*
+ bool fillNone = false;
+ bool strokeNone = false;
+ */
+ etk::String content;
+ // ---------------- get unique ID ----------------
+ m_id = _element.attributes["id"];
+ // ---------------- stroke ----------------
+ content = _element.attributes["stroke"];
+ if (content == "none") {
+ m_paint.stroke = etk::Pair, etk::String>(etk::color::none, "");
+ } else {
+ if (content.size()!=0) {
+ m_paint.stroke = parseColor(content);
+ }
+ content = _element.attributes["stroke-width"];
+ if (content.size()!=0) {
+ m_paint.strokeWidth = parseLength(content);
+ }
+ content = _element.attributes["stroke-opacity"];
+ if (content.size()!=0) {
+ float opacity = parseLength(content);
+ opacity = etk::avg(0.0f, opacity, 1.0f);
+ m_paint.stroke.first.setA(opacity);
+ }
+
+ content = _element.attributes["stroke-dasharray"];
+ if (content.size()!=0) {
+ if (content == "none" ) {
+ // OK, Nothing to do ...
+ } else {
+ ESVG_TODO(" 'stroke-dasharray' not implemented ...");
+ }
+ }
+ content = _element.attributes["stroke-linecap"];
+ if (content.size()!=0) {
+ if (content == "butt" ) {
+ m_paint.lineCap = esvg::cap_butt;
+ } else if (content == "round" ) {
+ m_paint.lineCap = esvg::cap_round;
+ } else if (content == "square" ) {
+ m_paint.lineCap = esvg::cap_square;
+ } else {
+ m_paint.lineCap = esvg::cap_butt;
+ Log.error("not know stroke-linecap value : \"" << content << "\", not in [butt,round,square]");
+ }
+ }
+ content = _element.attributes["stroke-linejoin"];
+ if (content.size()!=0) {
+ if (content == "miter" ) {
+ m_paint.lineJoin = esvg::join_miter;
+ } else if (content == "round" ) {
+ m_paint.lineJoin = esvg::join_round;
+ } else if (content == "bevel" ) {
+ m_paint.lineJoin = esvg::join_bevel;
+ } else {
+ m_paint.lineJoin = esvg::join_miter;
+ Log.error("not know stroke-linejoin value : \"" << content << "\", not in [miter,round,bevel]");
+ }
+ }
+ content = _element.attributes["stroke-miterlimit"];
+ if (content.size()!=0) {
+ float tmp = parseLength(content);
+ m_paint.miterLimit = etk::max(0.0f, tmp);
+ }
+ }
+ // ---------------- FILL ----------------
+ content = _element.attributes["fill"];
+ if (content == "none") {
+ m_paint.fill = etk::Pair, etk::String>(etk::color::none, "");
+ } else {
+ if (content.size()!=0) {
+ m_paint.fill = parseColor(content);
+ }
+ content = _element.attributes["fill-opacity"];
+ if (content.size()!=0) {
+ float opacity = parseLength(content);
+ opacity = etk::avg(0.0f, opacity, 1.0f);
+ m_paint.fill.first.setA(opacity);
+ }
+ content = _element.attributes["fill-rule"];
+ if (content.size()!=0) {
+ if (content == "nonzero") {
+ m_paint.flagEvenOdd = false;
+ } else if (content == "evenodd" ) {
+ m_paint.flagEvenOdd = true;
+ } else {
+ Log.error("not know fill-rule value : \"" << content << "\", not in [nonzero,evenodd]");
+ }
+ }
+ // ---------------- opacity ----------------
+ content = _element.attributes["opacity"];
+ if (content.size()!=0) {
+ m_paint.opacity = parseLength(content);
+ m_paint.opacity = etk::avg(0.0f, m_paint.opacity, 1.0f);
+ }
+ }
+}
+
+etk::Pair, etk::String> esvg::Base::parseColor(const etk::String& _inputData) {
+ etk::Pair, etk::String> localColor(etk::color::white, "");
+
+ if( _inputData.size() > 4
+ && _inputData[0] == 'u'
+ && _inputData[1] == 'r'
+ && _inputData[2] == 'l'
+ && _inputData[3] == '(') {
+ if (_inputData[4] == '#') {
+ etk::String color(_inputData.begin() + 5, _inputData.end()-1);
+ localColor = etk::Pair, etk::String>(etk::color::none, color);
+ } else {
+ Log.error("Problem in parsing the color : \"" << _inputData << "\" == > url(XXX) is not supported now ...");
+ }
+ } else {
+ localColor = etk::Pair, etk::String>(_inputData, "");
+ }
+ Log.verbose("Parse color : \"" << _inputData << "\" == > " << localColor.first << " " << localColor.second);
+ return localColor;
+}
+
+bool esvg::Base::parseXML(const exml::Element& _element, mat2x3& _parentTrans, vec2& _sizeMax) {
+ // TODO : UNDERSTAND why nothing is done here ...
+ // Parse basic elements (ID...):
+ m_id = _element.attributes["id"];
+ _sizeMax = vec2(0.0f, 0.0f);
+ return false;
+}
+
+
+const char * esvg::Base::spacingDist(int32_t _spacing) {
+ static const char *tmpValue = " ";
+ if (_spacing>20) {
+ _spacing = 20;
+ }
+ return tmpValue + 20*4 - _spacing*4;
+}
+
+void esvg::Base::draw(esvg::Renderer& _myRenderer, mat2x3& _basicTrans, int32_t _level) {
+ Log.warning(spacingDist(_level) << "DRAW esvg::Base ... ==> No drawing availlable");
+}
+
+
+
+const etk::String& esvg::Base::getId() const {
+ return m_id;
+}
+
+void esvg::Base::setId(const etk::String& _newId) {
+ // TODO : Check if it is UNIQUE ...
+ m_id = _newId;
+}
+
+
+void esvg::Base::drawShapePoints(etk::Vector>& _out,
+ int32_t _recurtionMax,
+ float _threshold,
+ mat2x3& _basicTrans,
+ int32_t _level) {
+
+}
+
diff --git a/src/org/atriasoft/esvg/Base.java b/src/org/atriasoft/esvg/Base.java
new file mode 100644
index 0000000..986c12b
--- /dev/null
+++ b/src/org/atriasoft/esvg/Base.java
@@ -0,0 +1,129 @@
+/** @file
+ * @author Edouard DUPIN
+ * @copyright 2011, Edouard DUPIN, all right reserved
+ * @license MPL v2.0 (see license file)
+ */
+
+
+#include
+#include
+
+#pragma once
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+
+namespace esvg {
+ extern const float kappa90; //!< proportional lenght to the radius of a bezier handle for 90° arcs.
+ /**
+ * @brief Painting mode of the Object:
+ */
+ enum paint {
+ paint_none, //!< No painting.
+ paint_color, //!< Painting a color.
+ paint_gradientLinear, //!< Painting a linear gradient.
+ paint_gradientRadial //!< Painting a radial gradient.
+ };
+
+ class PaintState {
+ public:
+ PaintState();
+ void clear();
+ public:
+ etk::Pair, etk::String> fill;
+ etk::Pair, etk::String> stroke;
+ float strokeWidth;
+ bool flagEvenOdd; //!< Fill rules
+ enum esvg::cap lineCap;
+ enum esvg::join lineJoin;
+ float miterLimit;
+ etk::Pair viewPort; //!< min pos, max pos
+ float opacity;
+ };
+
+ class Base {
+ protected:
+ PaintState m_paint;
+ mat2x3 m_transformMatrix; //!< specific render of the curent element
+ const char * spacingDist(int32_t _spacing);
+ public:
+ Base() {};
+ Base(PaintState _parentPaintState);
+ virtual ~Base() { };
+ /**
+ * @brief parse all the element needed in the basic node
+ * @param[in] _element standart XML node
+ * @return true if no problem arrived
+ */
+ virtual bool parseXML(const exml::Element& _element, mat2x3& _parentTrans, vec2& _sizeMax);
+ /**
+ * @brief Draw the form in the renderer
+ * @param[in] _myRenderer Renderer engine
+ * @param[in] _basicTrans Parant transformation of the environement
+ * @param[in] _level Level of the tree
+ */
+ virtual void draw(esvg::Renderer& _myRenderer, mat2x3& _basicTrans, int32_t _level=1);
+ /**
+ * @brief Draw rhe shape with all points
+ * @param[in] _out where the lines are added
+ * @param[in] _recurtionMax interpolation recurtion max
+ * @param[in] _threshold threshold to stop recurtion
+ * @param[in] _basicTrans Parant transformation of the environement
+ * @param[in] _level Level of the tree
+ */
+ virtual void drawShapePoints(etk::Vector>& _out,
+ int32_t _recurtionMax,
+ float _threshold,
+ mat2x3& _basicTrans,
+ int32_t _level=1);
+
+ virtual void display(int32_t _spacing) { };
+ void parseTransform(const exml::Element& _element);
+ /**
+ * @brief parse x, y, width, height attribute of the xml node
+ * @param[in] _element XML node
+ * @param[out] _pos parsed position
+ * @param[out] _size parsed dimention
+ */
+ void parsePosition(const exml::Element& _element, vec2 &_pos, vec2 &_size);
+ /**
+ * @brief parse a lenght of the xml element
+ * @param[in] _dataInput Data C String with the printed lenght
+ * @return standard number of pixels
+ */
+ float parseLength(const etk::String& _dataInput);
+ etk::Pair parseLength2(const etk::String& _dataInput);
+ /**
+ * @brief parse a Painting attribute of a specific node
+ * @param[in] _element Basic node of the XML that might be parsed
+ */
+ void parsePaintAttr(const exml::Element& _element);
+ /**
+ * @brief parse a color specification from the svg file
+ * @param[in] _inputData Data C String with the xml definition
+ * @return The parsed color (color used and the link if needed)
+ */
+ etk::Pair, etk::String> parseColor(const etk::String& _inputData);
+ protected:
+ etk::String m_id; //!< unique ID of the element.
+ public:
+ /**
+ * @brief Get the ID of the Element
+ * @return UniqueId in the svg file
+ */
+ const etk::String& getId() const;
+ /**
+ * @brief Set the ID of the Element
+ * @param[in] _newId New Id of the element
+ */
+ void setId(const etk::String& _newId);
+ };
+};
diff --git a/src/org/atriasoft/esvg/Circle.cpp b/src/org/atriasoft/esvg/Circle.cpp
new file mode 100644
index 0000000..b92ab65
--- /dev/null
+++ b/src/org/atriasoft/esvg/Circle.cpp
@@ -0,0 +1,166 @@
+/** @file
+ * @author Edouard DUPIN
+ * @copyright 2011, Edouard DUPIN, all right reserved
+ * @license MPL v2.0 (see license file)
+ */
+
+#include
+#include
+#include
+#include
+
+esvg::Circle::Circle(PaintState _parentPaintState) : esvg::Base(_parentPaintState) {
+
+}
+
+esvg::Circle::~Circle() {
+
+}
+
+bool esvg::Circle::parseXML(const exml::Element& _element, mat2x3& _parentTrans, vec2& _sizeMax) {
+ m_radius = 0.0;
+ m_position.setValue(0,0);
+ if (_element.exist() == false) {
+ return false;
+ }
+ parseTransform(_element);
+ parsePaintAttr(_element);
+
+ // add the property of the parrent modifications ...
+ m_transformMatrix *= _parentTrans;
+
+ etk::String content = _element.attributes["cx"];
+ if (content.size()!=0) {
+ m_position.setX(parseLength(content));
+ }
+ content = _element.attributes["cy"];
+ if (content.size()!=0) {
+ m_position.setY(parseLength(content));
+ }
+ content = _element.attributes["r"];
+ if (content.size()!=0) {
+ m_radius = parseLength(content);
+ } else {
+ Log.error("(l "<<_element.getPos()<<") Circle \"r\" is not present");
+ return false;
+ }
+ if (0 > m_radius) {
+ m_radius = 0;
+ Log.error("(l "<<_element.getPos()<<") Circle \"r\" is negative");
+ return false;
+ }
+ _sizeMax.setValue(m_position.x() + m_radius, m_position.y() + m_radius);
+ return true;
+}
+
+void esvg::Circle::display(int32_t _spacing) {
+ Log.debug(spacingDist(_spacing) << "Circle " << m_position << " radius=" << m_radius);
+}
+
+esvg::render::Path esvg::Circle::createPath() {
+ esvg::render::Path out;
+
+ out.clear();
+ out.moveTo(false, m_position + vec2(m_radius, 0.0f));
+ out.curveTo(false,
+ m_position + vec2(m_radius, m_radius*esvg::kappa90),
+ m_position + vec2(m_radius*esvg::kappa90, m_radius),
+ m_position + vec2(0.0f, m_radius));
+ out.curveTo(false,
+ m_position + vec2(-m_radius*esvg::kappa90, m_radius),
+ m_position + vec2(-m_radius, m_radius*esvg::kappa90),
+ m_position + vec2(-m_radius, 0.0f));
+ out.curveTo(false,
+ m_position + vec2(-m_radius, -m_radius*esvg::kappa90),
+ m_position + vec2(-m_radius*esvg::kappa90, -m_radius),
+ m_position + vec2(0.0f, -m_radius));
+ out.curveTo(false,
+ m_position + vec2(m_radius*esvg::kappa90, -m_radius),
+ m_position + vec2(m_radius, -m_radius*esvg::kappa90),
+ m_position + vec2(m_radius, 0.0f));
+ out.close();
+ return out;
+}
+
+void esvg::Circle::draw(esvg::Renderer& _myRenderer, mat2x3& _basicTrans, int32_t _level) {
+ Log.verbose(spacingDist(_level) << "DRAW esvg::Circle");
+ if (m_radius <= 0.0f) {
+ Log.verbose(spacingDist(_level+1) << "Too small radius" << m_radius);
+ return;
+ }
+ esvg::render::Path listElement = createPath();
+
+ mat2x3 mtx = m_transformMatrix;
+ mtx *= _basicTrans;
+
+ esvg::render::PointList listPoints;
+ listPoints = listElement.generateListPoints(_level,
+ _myRenderer.getInterpolationRecurtionMax(),
+ _myRenderer.getInterpolationThreshold());
+ //listPoints.applyMatrix(mtx);
+ esvg::render::SegmentList listSegmentFill;
+ esvg::render::SegmentList listSegmentStroke;
+ esvg::render::Weight tmpFill;
+ esvg::render::Weight tmpStroke;
+ ememory::SharedPtr colorFill = esvg::render::createColor(m_paint.fill, mtx);
+ ememory::SharedPtr colorStroke;
+ if (m_paint.strokeWidth > 0.0f) {
+ colorStroke = esvg::render::createColor(m_paint.stroke, mtx);
+ }
+ // Check if we need to display background
+ if (colorFill != null) {
+ listSegmentFill.createSegmentList(listPoints);
+ colorFill->setViewPort(listSegmentFill.getViewPort());
+ listSegmentFill.applyMatrix(mtx);
+ // now, traverse the scanlines and find the intersections on each scanline, use non-zero rule
+ tmpFill.generate(_myRenderer.getSize(),
+ _myRenderer.getNumberSubScanLine(),
+ listSegmentFill);
+ }
+ // check if we need to display stroke:
+ if (colorStroke != null) {
+ listSegmentStroke.createSegmentListStroke(listPoints,
+ m_paint.strokeWidth,
+ m_paint.lineCap,
+ m_paint.lineJoin,
+ m_paint.miterLimit);
+ colorStroke->setViewPort(listSegmentStroke.getViewPort());
+ listSegmentStroke.applyMatrix(mtx);
+ // now, traverse the scanlines and find the intersections on each scanline, use non-zero rule
+ tmpStroke.generate(_myRenderer.getSize(),
+ _myRenderer.getNumberSubScanLine(),
+ listSegmentStroke);
+ }
+ // add on images:
+ _myRenderer.print(tmpFill,
+ colorFill,
+ tmpStroke,
+ colorStroke,
+ m_paint.opacity);
+ #ifdef DEBUG
+ _myRenderer.addDebugSegment(listSegmentFill);
+ _myRenderer.addDebugSegment(listSegmentStroke);
+ #endif
+}
+
+void esvg::Circle::drawShapePoints(etk::Vector>& _out,
+ int32_t _recurtionMax,
+ float _threshold,
+ mat2x3& _basicTrans,
+ int32_t _level) {
+ Log.verbose(spacingDist(_level) << "DRAW Shape esvg::Circle");
+ esvg::render::Path listElement = createPath();
+ mat2x3 mtx = m_transformMatrix;
+ mtx *= _basicTrans;
+ esvg::render::PointList listPoints;
+ listPoints = listElement.generateListPoints(_level, _recurtionMax, _threshold);
+ listPoints.applyMatrix(mtx);
+ for (auto &it : listPoints.m_data) {
+ etk::Vector listPoint;
+ for (auto &itDot : it) {
+ listPoint.pushBack(itDot.m_pos);
+ }
+ _out.pushBack(listPoint);
+ }
+}
+
diff --git a/src/org/atriasoft/esvg/Circle.java b/src/org/atriasoft/esvg/Circle.java
new file mode 100644
index 0000000..ad01971
--- /dev/null
+++ b/src/org/atriasoft/esvg/Circle.java
@@ -0,0 +1,31 @@
+/** @file
+ * @author Edouard DUPIN
+ * @copyright 2011, Edouard DUPIN, all right reserved
+ * @license MPL v2.0 (see license file)
+ */
+#pragma once
+
+#include
+
+namespace esvg {
+ class Circle : public esvg::Base {
+ private:
+ vec2 m_position; //!< Position of the Circle
+ float m_radius; //!< Radius of the Circle
+ public:
+ Circle(PaintState _parentPaintState);
+ ~Circle();
+ bool parseXML(const exml::Element& _element, mat2x3& _parentTrans, vec2& _sizeMax) override;
+ void display(int32_t _spacing) override;
+ void draw(esvg::Renderer& _myRenderer, mat2x3& _basicTrans, int32_t _level) override;
+ void drawShapePoints(etk::Vector>& _out,
+ int32_t _recurtionMax,
+ float _threshold,
+ mat2x3& _basicTrans,
+ int32_t _level=1) override;
+ private:
+ esvg::render::Path createPath();
+ };
+}
+
+
diff --git a/src/org/atriasoft/esvg/Dimension.cpp b/src/org/atriasoft/esvg/Dimension.cpp
new file mode 100644
index 0000000..f11770f
--- /dev/null
+++ b/src/org/atriasoft/esvg/Dimension.cpp
@@ -0,0 +1,445 @@
+/** @file
+ * @author Edouard DUPIN
+ * @copyright 2011, Edouard DUPIN, all right reserved
+ * @license MPL v2.0 (see license file)
+ */
+
+#include
+#include
+
+static const float inchToMillimeter = 1.0f/25.4f;
+static const float footToMillimeter = 1.0f/304.8f;
+static const float meterToMillimeter = 1.0f/1000.0f;
+static const float centimeterToMillimeter = 1.0f/10.0f;
+static const float kilometerToMillimeter = 1.0f/1000000.0f;
+static const float millimeterToInch = 25.4f;
+static const float millimeterToFoot = 304.8f;
+static const float millimeterToMeter =1000.0f;
+static const float millimeterToCentimeter = 10.0f;
+static const float millimeterToKilometer = 1000000.0f;
+
+// 72 px /inch(2.54cm)
+static const float basicRatio = 72.0f / 25.4f;
+
+esvg::Dimension::Dimension() :
+ m_data(0,0),
+ m_type(esvg::distance_pixel) {
+ // notinh to do ...
+}
+
+esvg::Dimension::Dimension(const vec2& _size, enum esvg::distance _type) :
+ m_data(0,0),
+ m_type(esvg::distance_pixel) {
+ set(_size, _type);
+}
+
+void esvg::Dimension::set(etk::String _config) {
+ m_data.setValue(0,0);
+ m_type = esvg::distance_pixel;
+ enum distance type = esvg::distance_pixel;
+ if (etk::end_with(_config, "%", false) == true) {
+ type = esvg::distance_pourcent;
+ _config.erase(_config.size()-1, 1);
+ } else if (etk::end_with(_config, "px",false) == true) {
+ type = esvg::distance_pixel;
+ _config.erase(_config.size()-2, 2);
+ } else if (etk::end_with(_config, "ft",false) == true) {
+ type = esvg::distance_foot;
+ _config.erase(_config.size()-2, 2);
+ } else if (etk::end_with(_config, "in",false) == true) {
+ type = esvg::distance_inch;
+ _config.erase(_config.size()-2, 2);
+ } else if (etk::end_with(_config, "km",false) == true) {
+ type = esvg::distance_kilometer;
+ _config.erase(_config.size()-2, 2);
+ } else if (etk::end_with(_config, "mm",false) == true) {
+ type = esvg::distance_millimeter;
+ _config.erase(_config.size()-2, 2);
+ } else if (etk::end_with(_config, "cm",false) == true) {
+ type = esvg::distance_centimeter;
+ _config.erase(_config.size()-2, 2);
+ } else if (etk::end_with(_config, "m",false) == true) {
+ type = esvg::distance_meter;
+ _config.erase(_config.size()-1, 1);
+ } else {
+ type = esvg::distance_pixel;
+ Log.verbose("default dimention type for: '" << _config << "' ==> pixel");
+ return;
+ }
+ vec2 tmp = _config;
+ set(tmp, type);
+ Log.verbose(" config dimention : \"" << _config << "\" == > " << *this );
+}
+
+static enum esvg::distance parseType(etk::String& _config) {
+ enum esvg::distance type = esvg::distance_pixel;
+ if (etk::end_with(_config, "%", false) == true) {
+ type = esvg::distance_pourcent;
+ _config.erase(_config.size()-1, 1);
+ } else if (etk::end_with(_config, "px",false) == true) {
+ type = esvg::distance_pixel;
+ _config.erase(_config.size()-2, 2);
+ } else if (etk::end_with(_config, "ft",false) == true) {
+ type = esvg::distance_foot;
+ _config.erase(_config.size()-2, 2);
+ } else if (etk::end_with(_config, "in",false) == true) {
+ type = esvg::distance_inch;
+ _config.erase(_config.size()-2, 2);
+ } else if (etk::end_with(_config, "km",false) == true) {
+ type = esvg::distance_kilometer;
+ _config.erase(_config.size()-2, 2);
+ } else if (etk::end_with(_config, "mm",false) == true) {
+ type = esvg::distance_millimeter;
+ _config.erase(_config.size()-2, 2);
+ } else if (etk::end_with(_config, "cm",false) == true) {
+ type = esvg::distance_centimeter;
+ _config.erase(_config.size()-2, 2);
+ } else if (etk::end_with(_config, "m",false) == true) {
+ type = esvg::distance_meter;
+ _config.erase(_config.size()-1, 1);
+ } else {
+ type = esvg::distance_pixel;
+ Log.verbose("default dimention type for: '" << _config << "' ==> pixel");
+ }
+ return type;
+}
+
+
+void esvg::Dimension::set(etk::String _configX, etk::String _configY) {
+ m_data.setValue(0,0);
+ m_type = esvg::distance_pixel;
+ enum distance type = esvg::distance_pixel;
+ // First Parse X
+ enum distance typeX = parseType(_configX);
+ float valueX = etk::string_to_float(_configX);
+ // Second Parse Y
+ enum distance typeY = parseType(_configY);
+ float valueY = etk::string_to_float(_configY);
+ // TODO : Check difference ...
+ set(vec2(valueX, valueY), typeX);
+ Log.verbose(" config dimention : '" << _configX << "' '" << _configY << "' == > " << *this );
+}
+
+
+esvg::Dimension::~Dimension() {
+ // nothing to do ...
+}
+
+esvg::Dimension::operator etk::String() const {
+ etk::String str;
+ str = getValue();
+ switch(getType()) {
+ case esvg::distance_pourcent:
+ str += "%";
+ break;
+ case esvg::distance_pixel:
+ str += "px";
+ break;
+ case esvg::distance_meter:
+ str += "m";
+ break;
+ case esvg::distance_centimeter:
+ str += "cm";
+ break;
+ case esvg::distance_millimeter:
+ str += "mm";
+ break;
+ case esvg::distance_kilometer:
+ str += "km";
+ break;
+ case esvg::distance_inch:
+ str += "in";
+ break;
+ case esvg::distance_foot:
+ str += "ft";
+ break;
+ case esvg::distance_element:
+ str += "em";
+ break;
+ case esvg::distance_ex:
+ str += "ex";
+ break;
+ case esvg::distance_point:
+ str += "pt";
+ break;
+ case esvg::distance_pc:
+ str += "pc";
+ break;
+ }
+ return str;
+}
+
+void esvg::Dimension::set(const vec2& _size, enum esvg::distance _type) {
+ m_data = _size;
+ m_type = _type;
+ switch(_type) {
+ case esvg::distance_pourcent:
+ case esvg::distance_pixel:
+ // nothing to do: Supported ...
+ break;
+ case esvg::distance_meter:
+ case esvg::distance_centimeter:
+ case esvg::distance_millimeter:
+ case esvg::distance_kilometer:
+ case esvg::distance_inch:
+ case esvg::distance_foot:
+ case esvg::distance_element:
+ case esvg::distance_ex:
+ case esvg::distance_point:
+ case esvg::distance_pc:
+ Log.error("Does not support other than Px and % type of dimention : " << _type << " automaticly convert with {72,72} pixel/inch");
+ break;
+ }
+}
+
+vec2 esvg::Dimension::getPixel(const vec2& _upperSize) const {
+ switch(m_type) {
+ case esvg::distance_pourcent:
+ return vec2(_upperSize.x()*m_data.x()*0.01f, _upperSize.y()*m_data.y()*0.01f);
+ case esvg::distance_pixel:
+ return m_data;
+ case esvg::distance_meter:
+ return vec2(m_data.x()*meterToMillimeter*basicRatio, m_data.y()*meterToMillimeter*basicRatio);
+ case esvg::distance_centimeter:
+ return vec2(m_data.x()*centimeterToMillimeter*basicRatio, m_data.y()*centimeterToMillimeter*basicRatio);
+ case esvg::distance_millimeter:
+ return vec2(m_data.x()*basicRatio, m_data.y()*basicRatio);
+ case esvg::distance_kilometer:
+ return vec2(m_data.x()*kilometerToMillimeter*basicRatio, m_data.y()*kilometerToMillimeter*basicRatio);
+ case esvg::distance_inch:
+ return vec2(m_data.x()*inchToMillimeter*basicRatio, m_data.y()*inchToMillimeter*basicRatio);
+ case esvg::distance_foot:
+ return vec2(m_data.x()*footToMillimeter*basicRatio, m_data.y()*footToMillimeter*basicRatio);
+ }
+ return vec2(128.0f, 128.0f);
+}
+
+etk::Stream& esvg::operator <<(etk::Stream& _os, enum esvg::distance _obj) {
+ switch(_obj) {
+ case esvg::distance_pourcent:
+ _os << "%";
+ break;
+ case esvg::distance_pixel:
+ _os << "px";
+ break;
+ case esvg::distance_meter:
+ _os << "m";
+ break;
+ case esvg::distance_centimeter:
+ _os << "cm";
+ break;
+ case esvg::distance_millimeter:
+ _os << "mm";
+ break;
+ case esvg::distance_kilometer:
+ _os << "km";
+ break;
+ case esvg::distance_inch:
+ _os << "in";
+ break;
+ case esvg::distance_foot:
+ _os << "ft";
+ break;
+ case esvg::distance_element:
+ _os << "em";
+ break;
+ case esvg::distance_ex:
+ _os << "ex";
+ break;
+ case esvg::distance_point:
+ _os << "pt";
+ break;
+ case esvg::distance_pc:
+ _os << "pc";
+ break;
+ }
+ return _os;
+}
+
+etk::Stream& esvg::operator <<(etk::Stream& _os, const esvg::Dimension& _obj) {
+ _os << _obj.getValue() << _obj.getType();
+ return _os;
+}
+
+namespace etk {
+ template<> etk::String toString(const esvg::Dimension& _obj) {
+ return _obj;
+ }
+ template<> etk::UString toUString(const esvg::Dimension& _obj) {
+ return etk::toUString(etk::toString(_obj));
+ }
+ template<> bool from_string(esvg::Dimension& _variableRet, const etk::String& _value) {
+ _variableRet = esvg::Dimension(_value);
+ return true;
+ }
+ template<> bool from_string(esvg::Dimension& _variableRet, const etk::UString& _value) {
+ return from_string(_variableRet, etk::toString(_value));
+ }
+};
+
+esvg::Dimension1D::Dimension1D() :
+ m_data(0.0f),
+ m_type(esvg::distance_pixel) {
+ // notinh to do ...
+}
+
+esvg::Dimension1D::Dimension1D(float _size, enum esvg::distance _type) :
+ m_data(0.0f),
+ m_type(esvg::distance_pixel) {
+ set(_size, _type);
+}
+
+void esvg::Dimension1D::set(etk::String _config) {
+ m_data = 0;
+ m_type = esvg::distance_pixel;
+ enum distance type = esvg::distance_pixel;
+ if (etk::end_with(_config, "%", false) == true) {
+ type = esvg::distance_pourcent;
+ _config.erase(_config.size()-1, 1);
+ } else if (etk::end_with(_config, "px",false) == true) {
+ type = esvg::distance_pixel;
+ _config.erase(_config.size()-2, 2);
+ } else if (etk::end_with(_config, "ft",false) == true) {
+ type = esvg::distance_foot;
+ _config.erase(_config.size()-2, 2);
+ } else if (etk::end_with(_config, "in",false) == true) {
+ type = esvg::distance_inch;
+ _config.erase(_config.size()-2, 2);
+ } else if (etk::end_with(_config, "km",false) == true) {
+ type = esvg::distance_kilometer;
+ _config.erase(_config.size()-2, 2);
+ } else if (etk::end_with(_config, "mm",false) == true) {
+ type = esvg::distance_millimeter;
+ _config.erase(_config.size()-2, 2);
+ } else if (etk::end_with(_config, "cm",false) == true) {
+ type = esvg::distance_centimeter;
+ _config.erase(_config.size()-2, 2);
+ } else if (etk::end_with(_config, "m",false) == true) {
+ type = esvg::distance_meter;
+ _config.erase(_config.size()-1, 1);
+ } else {
+ type = esvg::distance_pixel;
+ Log.verbose("default dimention type for: '" << _config << "' ==> pixel");
+ }
+ float tmp = etk::string_to_float(_config);
+ set(tmp, type);
+ Log.verbose(" config dimention : \"" << _config << "\" == > " << *this );
+}
+
+esvg::Dimension1D::~Dimension1D() {
+ // nothing to do ...
+}
+
+esvg::Dimension1D::operator etk::String() const {
+ etk::String str;
+ str = getValue();
+ switch(getType()) {
+ case esvg::distance_pourcent:
+ str += "%";
+ break;
+ case esvg::distance_pixel:
+ str += "px";
+ break;
+ case esvg::distance_meter:
+ str += "m";
+ break;
+ case esvg::distance_centimeter:
+ str += "cm";
+ break;
+ case esvg::distance_millimeter:
+ str += "mm";
+ break;
+ case esvg::distance_kilometer:
+ str += "km";
+ break;
+ case esvg::distance_inch:
+ str += "in";
+ break;
+ case esvg::distance_foot:
+ str += "ft";
+ break;
+ case esvg::distance_element:
+ str += "em";
+ break;
+ case esvg::distance_ex:
+ str += "ex";
+ break;
+ case esvg::distance_point:
+ str += "pt";
+ break;
+ case esvg::distance_pc:
+ str += "pc";
+ break;
+ }
+ return str;
+}
+
+void esvg::Dimension1D::set(float _size, enum esvg::distance _type) {
+ m_data = _size;
+ m_type = _type;
+ switch(_type) {
+ case esvg::distance_pourcent:
+ case esvg::distance_pixel:
+ // nothing to do: Supported ...
+ break;
+ case esvg::distance_meter:
+ case esvg::distance_centimeter:
+ case esvg::distance_millimeter:
+ case esvg::distance_kilometer:
+ case esvg::distance_inch:
+ case esvg::distance_foot:
+ case esvg::distance_element:
+ case esvg::distance_ex:
+ case esvg::distance_point:
+ case esvg::distance_pc:
+ Log.error("Does not support other than Px and % type of dimention1D : " << _type << " automaticly convert with {72,72} pixel/inch");
+ break;
+ }
+}
+
+float esvg::Dimension1D::getPixel(float _upperSize) const {
+ switch(m_type) {
+ case esvg::distance_pourcent:
+ return _upperSize*m_data*0.01f;
+ case esvg::distance_pixel:
+ return m_data;
+ case esvg::distance_meter:
+ return m_data*meterToMillimeter*basicRatio;
+ case esvg::distance_centimeter:
+ return m_data*centimeterToMillimeter*basicRatio;
+ case esvg::distance_millimeter:
+ return m_data*basicRatio;
+ case esvg::distance_kilometer:
+ return m_data*kilometerToMillimeter*basicRatio;
+ case esvg::distance_inch:
+ return m_data*inchToMillimeter*basicRatio;
+ case esvg::distance_foot:
+ return m_data*footToMillimeter*basicRatio;
+ }
+ return 128.0f;
+}
+
+etk::Stream& esvg::operator <<(etk::Stream& _os, const esvg::Dimension1D& _obj) {
+ _os << _obj.getValue() << _obj.getType();
+ return _os;
+}
+
+namespace etk {
+ template<> etk::String toString(const esvg::Dimension1D& _obj) {
+ return _obj;
+ }
+ template<> etk::UString toUString(const esvg::Dimension1D& _obj) {
+ return etk::toUString(etk::toString(_obj));
+ }
+ template<> bool from_string(esvg::Dimension1D& _variableRet, const etk::String& _value) {
+ _variableRet = esvg::Dimension1D(_value);
+ return true;
+ }
+ template<> bool from_string(esvg::Dimension1D& _variableRet, const etk::UString& _value) {
+ return from_string(_variableRet, etk::toString(_value));
+ }
+};
+
+
+
+
diff --git a/src/org/atriasoft/esvg/Dimension.java b/src/org/atriasoft/esvg/Dimension.java
new file mode 100644
index 0000000..73a7eec
--- /dev/null
+++ b/src/org/atriasoft/esvg/Dimension.java
@@ -0,0 +1,252 @@
+/** @file
+ * @author Edouard DUPIN
+ * @copyright 2011, Edouard DUPIN, all right reserved
+ * @license MPL v2.0 (see license file)
+ */
+#pragma once
+
+#include
+#include
+
+namespace esvg {
+ enum distance {
+ distance_pourcent=0, //!< "%"
+ distance_pixel, //!< "px"
+ distance_meter, //!< "m"
+ distance_centimeter, //!< "cm"
+ distance_millimeter, //!< "mm"
+ distance_kilometer, //!< "km"
+ distance_inch, //!< "in"
+ distance_foot, //!< "ft"
+ distance_element, //!< "em"
+ distance_ex, //!< "ex"
+ distance_point, //!< "pt"
+ distance_pc //!< "pc"
+ };
+ /**
+ * @brief in the dimention class we store the data as the more usefull unit (pixel)
+ * but one case need to be dynamic the %, then when requested in % the register the % value
+ */
+ class Dimension {
+ private:
+ vec2 m_data;
+ enum distance m_type;
+ public:
+ /**
+ * @brief Constructor (default :0,0 mode pixel)
+ */
+ Dimension();
+ /**
+ * @brief Constructor
+ * @param[in] _size Requested dimention
+ * @param[in] _type Unit of the Dimention
+ */
+ Dimension(const vec2& _size, enum esvg::distance _type=esvg::distance_pixel);
+ /**
+ * @brief Constructor
+ * @param[in] _config dimension configuration.
+ */
+ Dimension(const etk::String& _config) :
+ m_data(0,0),
+ m_type(esvg::distance_pixel) {
+ set(_config);
+ };
+ /**
+ * @brief Constructor
+ * @param[in] _configX dimension X configuration.
+ * @param[in] _configY dimension Y configuration.
+ */
+ Dimension(const etk::String& _configX, const etk::String& _configY) :
+ m_data(0,0),
+ m_type(esvg::distance_pixel) {
+ set(_configX, _configY);
+ };
+ /**
+ * @brief Destructor
+ */
+ ~Dimension();
+
+ /**
+ * @brief string cast :
+ */
+ operator etk::String() const;
+
+ /**
+ * @brief get the current dimention.
+ * @return dimention requested.
+ */
+ const vec2& getValue() const {
+ return m_data;
+ }
+ /**
+ * @breif get the dimension type
+ * @return the type
+ */
+ enum distance getType() const {
+ return m_type;
+ };
+ /**
+ * @brief set the current dimention in requested type
+ * @param[in] _size Dimention to set
+ * @param[in] _type Type of unit requested.
+ */
+ void set(const vec2& _size, enum distance _type);
+
+ public:
+ /**
+ * @brief set the current dimention in requested type
+ * @param[in] _config dimension configuration.
+ */
+ void set(etk::String _config);
+ /**
+ * @brief set the current dimention in requested type
+ * @param[in] _configX dimension X configuration.
+ * @param[in] _configY dimension Y configuration.
+ */
+ void set(etk::String _configX, etk::String _configY);
+ public:
+ /**
+ * @brief get the current dimention in pixel
+ * @param[in] _upperSize Size in pixel of the upper value
+ * @return dimention in Pixel
+ */
+ vec2 getPixel(const vec2& _upperSize) const;
+ /*****************************************************
+ * = assigment
+ *****************************************************/
+ const Dimension& operator= (const Dimension& _obj ) {
+ if (this!=&_obj) {
+ m_data = _obj.m_data;
+ m_type = _obj.m_type;
+ }
+ return *this;
+ }
+ /*****************************************************
+ * == operator
+ *****************************************************/
+ bool operator == (const Dimension& _obj) const {
+ if( m_data == _obj.m_data
+ && m_type == _obj.m_type) {
+ return true;
+ }
+ return false;
+ }
+ /*****************************************************
+ * != operator
+ *****************************************************/
+ bool operator!= (const Dimension& _obj) const {
+ if( m_data != _obj.m_data
+ || m_type != _obj.m_type) {
+ return true;
+ }
+ return false;
+ }
+ };
+ etk::Stream& operator <<(etk::Stream& _os, enum esvg::distance _obj);
+ etk::Stream& operator <<(etk::Stream& _os, const esvg::Dimension& _obj);
+ /**
+ * @brief in the dimention class we store the data as the more usefull unit (pixel)
+ * but one case need to be dynamic the %, then when requested in % the register the % value
+ */
+ class Dimension1D {
+ private:
+ float m_data;
+ enum distance m_type;
+ public:
+ /**
+ * @brief Constructor (default :0,0 mode pixel)
+ */
+ Dimension1D();
+ /**
+ * @brief Constructor
+ * @param[in] _size Requested dimention
+ * @param[in] _type Unit of the Dimention
+ */
+ Dimension1D(float _size, enum esvg::distance _type=esvg::distance_pixel);
+ /**
+ * @brief Constructor
+ * @param[in] _config dimension configuration.
+ */
+ Dimension1D(const etk::String& _config) :
+ m_data(0.0f),
+ m_type(esvg::distance_pixel) {
+ set(_config);
+ };
+ /**
+ * @brief Destructor
+ */
+ ~Dimension1D();
+
+ /**
+ * @brief string cast :
+ */
+ operator etk::String() const;
+
+ /**
+ * @brief get the current dimention.
+ * @return dimention requested.
+ */
+ const float& getValue() const {
+ return m_data;
+ }
+ /**
+ * @breif get the dimension type
+ * @return the type
+ */
+ enum distance getType() const {
+ return m_type;
+ };
+ /**
+ * @brief set the current dimention in requested type
+ * @param[in] _size Dimention to set
+ * @param[in] _type Type of unit requested.
+ */
+ void set(float _size, enum distance _type);
+
+ public:
+ /**
+ * @brief set the current dimention in requested type
+ * @param[in] _config dimension configuration.
+ */
+ void set(etk::String _config);
+ public:
+ /**
+ * @brief get the current dimention in pixel
+ * @param[in] _upperSize Size in pixel of the upper value
+ * @return dimention in Pixel
+ */
+ float getPixel(float _upperSize) const;
+ /*****************************************************
+ * = assigment
+ *****************************************************/
+ const Dimension1D& operator= (const Dimension1D& _obj ) {
+ if (this!=&_obj) {
+ m_data = _obj.m_data;
+ m_type = _obj.m_type;
+ }
+ return *this;
+ }
+ /*****************************************************
+ * == operator
+ *****************************************************/
+ bool operator == (const Dimension1D& _obj) const {
+ if( m_data == _obj.m_data
+ && m_type == _obj.m_type) {
+ return true;
+ }
+ return false;
+ }
+ /*****************************************************
+ * != operator
+ *****************************************************/
+ bool operator!= (const Dimension1D& _obj) const {
+ if( m_data != _obj.m_data
+ || m_type != _obj.m_type) {
+ return true;
+ }
+ return false;
+ }
+ };
+ etk::Stream& operator <<(etk::Stream& _os, const esvg::Dimension1D& _obj);
+}
+
diff --git a/src/org/atriasoft/esvg/Ellipse.cpp b/src/org/atriasoft/esvg/Ellipse.cpp
new file mode 100644
index 0000000..206a9f5
--- /dev/null
+++ b/src/org/atriasoft/esvg/Ellipse.cpp
@@ -0,0 +1,172 @@
+/** @file
+ * @author Edouard DUPIN
+ * @copyright 2011, Edouard DUPIN, all right reserved
+ * @license MPL v2.0 (see license file)
+ */
+
+#include
+#include
+#include
+#include
+
+esvg::Ellipse::Ellipse(PaintState _parentPaintState) : esvg::Base(_parentPaintState) {
+
+}
+
+esvg::Ellipse::~Ellipse() {
+
+}
+
+bool esvg::Ellipse::parseXML(const exml::Element& _element, mat2x3& _parentTrans, vec2& _sizeMax) {
+ if (_element.exist() == false) {
+ return false;
+ }
+ parseTransform(_element);
+ parsePaintAttr(_element);
+
+ // add the property of the parrent modifications ...
+ m_transformMatrix *= _parentTrans;
+
+ m_c.setValue(0,0);
+ m_r.setValue(0,0);
+
+ etk::String content = _element.attributes["cx"];
+ if (content.size()!=0) {
+ m_c.setX(parseLength(content));
+ }
+ content = _element.attributes["cy"];
+ if (content.size()!=0) {
+ m_c.setY(parseLength(content));
+ }
+ content = _element.attributes["rx"];
+ if (content.size()!=0) {
+ m_r.setX(parseLength(content));
+ } else {
+ Log.error("(l "<<_element.getPos()<<") Ellipse \"rx\" is not present");
+ return false;
+ }
+ content = _element.attributes["ry"];
+ if (content.size()!=0) {
+ m_r.setY(parseLength(content));
+ } else {
+ Log.error("(l "<<_element.getPos()<<") Ellipse \"ry\" is not present");
+ return false;
+ }
+ _sizeMax.setValue(m_c.x() + m_r.x(), m_c.y() + m_r.y());
+
+ return true;
+}
+
+void esvg::Ellipse::display(int32_t _spacing) {
+ Log.debug(spacingDist(_spacing) << "Ellipse c=" << m_c << " r=" << m_r);
+}
+
+
+esvg::render::Path esvg::Ellipse::createPath() {
+ esvg::render::Path out;
+ out.clear();
+ out.moveTo(false, m_c + vec2(m_r.x(), 0.0f));
+ out.curveTo(false,
+ m_c + vec2(m_r.x(), m_r.y()*esvg::kappa90),
+ m_c + vec2(m_r.x()*esvg::kappa90, m_r.y()),
+ m_c + vec2(0.0f, m_r.y()));
+ out.curveTo(false,
+ m_c + vec2(-m_r.x()*esvg::kappa90, m_r.y()),
+ m_c + vec2(-m_r.x(), m_r.y()*esvg::kappa90),
+ m_c + vec2(-m_r.x(), 0.0f));
+ out.curveTo(false,
+ m_c + vec2(-m_r.x(), -m_r.y()*esvg::kappa90),
+ m_c + vec2(-m_r.x()*esvg::kappa90, -m_r.y()),
+ m_c + vec2(0.0f, -m_r.y()));
+ out.curveTo(false,
+ m_c + vec2(m_r.x()*esvg::kappa90, -m_r.y()),
+ m_c + vec2(m_r.x(), -m_r.y()*esvg::kappa90),
+ m_c + vec2(m_r.x(), 0.0f));
+ out.close();
+ return out;
+}
+
+void esvg::Ellipse::draw(esvg::Renderer& _myRenderer, mat2x3& _basicTrans, int32_t _level) {
+ Log.verbose(spacingDist(_level) << "DRAW esvg::Ellipse");
+ if ( m_r.x()<=0.0f
+ || m_r.y()<=0.0f) {
+ Log.verbose(spacingDist(_level+1) << "Too small radius" << m_r);
+ return;
+ }
+ esvg::render::Path listElement = createPath();
+
+ mat2x3 mtx = m_transformMatrix;
+ mtx *= _basicTrans;
+
+ esvg::render::PointList listPoints;
+ listPoints = listElement.generateListPoints(_level,
+ _myRenderer.getInterpolationRecurtionMax(),
+ _myRenderer.getInterpolationThreshold());
+ //listPoints.applyMatrix(mtx);
+ esvg::render::SegmentList listSegmentFill;
+ esvg::render::SegmentList listSegmentStroke;
+ esvg::render::Weight tmpFill;
+ esvg::render::Weight tmpStroke;
+ ememory::SharedPtr colorFill = esvg::render::createColor(m_paint.fill, mtx);
+ ememory::SharedPtr colorStroke;
+ if (m_paint.strokeWidth > 0.0f) {
+ colorStroke = esvg::render::createColor(m_paint.stroke, mtx);
+ }
+ // Check if we need to display background
+ if (colorFill != null) {
+ listSegmentFill.createSegmentList(listPoints);
+ colorFill->setViewPort(listSegmentFill.getViewPort());
+ listSegmentFill.applyMatrix(mtx);
+ // now, traverse the scanlines and find the intersections on each scanline, use non-zero rule
+ tmpFill.generate(_myRenderer.getSize(),
+ _myRenderer.getNumberSubScanLine(),
+ listSegmentFill);
+ }
+ // check if we need to display stroke:
+ if (colorStroke != null) {
+ listSegmentStroke.createSegmentListStroke(listPoints,
+ m_paint.strokeWidth,
+ m_paint.lineCap,
+ m_paint.lineJoin,
+ m_paint.miterLimit);
+ colorStroke->setViewPort(listSegmentStroke.getViewPort());
+ listSegmentStroke.applyMatrix(mtx);
+ // now, traverse the scanlines and find the intersections on each scanline, use non-zero rule
+ tmpStroke.generate(_myRenderer.getSize(),
+ _myRenderer.getNumberSubScanLine(),
+ listSegmentStroke);
+ }
+ // add on images:
+ _myRenderer.print(tmpFill,
+ colorFill,
+ tmpStroke,
+ colorStroke,
+ m_paint.opacity);
+ #ifdef DEBUG
+ _myRenderer.addDebugSegment(listSegmentFill);
+ _myRenderer.addDebugSegment(listSegmentStroke);
+ #endif
+}
+
+
+void esvg::Ellipse::drawShapePoints(etk::Vector>& _out,
+ int32_t _recurtionMax,
+ float _threshold,
+ mat2x3& _basicTrans,
+ int32_t _level) {
+ Log.verbose(spacingDist(_level) << "DRAW Shape esvg::Ellipse");
+ esvg::render::Path listElement = createPath();
+ mat2x3 mtx = m_transformMatrix;
+ mtx *= _basicTrans;
+ esvg::render::PointList listPoints;
+ listPoints = listElement.generateListPoints(_level, _recurtionMax, _threshold);
+ listPoints.applyMatrix(mtx);
+ for (auto &it : listPoints.m_data) {
+ etk::Vector listPoint;
+ for (auto &itDot : it) {
+ listPoint.pushBack(itDot.m_pos);
+ }
+ _out.pushBack(listPoint);
+ }
+}
+
diff --git a/src/org/atriasoft/esvg/Ellipse.java b/src/org/atriasoft/esvg/Ellipse.java
new file mode 100644
index 0000000..02ac432
--- /dev/null
+++ b/src/org/atriasoft/esvg/Ellipse.java
@@ -0,0 +1,30 @@
+/** @file
+ * @author Edouard DUPIN
+ * @copyright 2011, Edouard DUPIN, all right reserved
+ * @license MPL v2.0 (see license file)
+ */
+#pragma once
+
+#include
+
+namespace esvg {
+ class Ellipse : public esvg::Base {
+ private:
+ vec2 m_c; //!< Center property of the ellipse
+ vec2 m_r; //!< Radius property of the ellipse
+ public:
+ Ellipse(PaintState _parentPaintState);
+ ~Ellipse();
+ bool parseXML(const exml::Element& _element, mat2x3& _parentTrans, vec2& _sizeMax) override;
+ void display(int32_t _spacing) override;
+ void draw(esvg::Renderer& _myRenderer, mat2x3& _basicTrans, int32_t _level) override;
+ void drawShapePoints(etk::Vector>& _out,
+ int32_t _recurtionMax,
+ float _threshold,
+ mat2x3& _basicTrans,
+ int32_t _level=1) override;
+ private:
+ esvg::render::Path createPath();
+ };
+}
+
diff --git a/src/org/atriasoft/esvg/Group.cpp b/src/org/atriasoft/esvg/Group.cpp
new file mode 100644
index 0000000..98fac79
--- /dev/null
+++ b/src/org/atriasoft/esvg/Group.cpp
@@ -0,0 +1,129 @@
+/** @file
+ * @author Edouard DUPIN
+ * @copyright 2011, Edouard DUPIN, all right reserved
+ * @license MPL v2.0 (see license file)
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+esvg::Group::Group(PaintState _parentPaintState) : esvg::Base(_parentPaintState) {
+
+}
+
+esvg::Group::~Group() {
+
+}
+
+bool esvg::Group::parseXML(const exml::Element& _element, mat2x3& _parentTrans, vec2& _sizeMax) {
+ if (_element.exist() == false) {
+ return false;
+ }
+ // parse ...
+ vec2 pos(0,0);
+ vec2 size(0,0);
+ parseTransform(_element);
+ parsePosition(_element, pos, size);
+ parsePaintAttr(_element);
+ Log.verbose("parsed G1. trans : " << m_transformMatrix);
+
+ // add the property of the parrent modifications ...
+ m_transformMatrix *= _parentTrans;
+
+ Log.verbose("parsed G2. trans : " << m_transformMatrix);
+
+ _sizeMax.setValue(0,0);
+ vec2 tmpPos(0,0);
+ // parse all sub node :
+ for(const auto it : _element.nodes) {
+ exml::Element child = it.toElement();
+ if (child.exist() == false) {
+ // can be a comment ...
+ continue;
+ }
+ ememory::SharedPtr elementParser;
+ if (child.getValue() == "g") {
+ elementParser = ememory::makeShared(m_paint);
+ } else if (child.getValue() == "a") {
+ // TODO ...
+ } else if (child.getValue() == "path") {
+ elementParser = ememory::makeShared(m_paint);
+ } else if (child.getValue() == "rect") {
+ elementParser = ememory::makeShared(m_paint);
+ } else if (child.getValue() == "circle") {
+ elementParser = ememory::makeShared(m_paint);
+ } else if (child.getValue() == "ellipse") {
+ elementParser = ememory::makeShared(m_paint);
+ } else if (child.getValue() == "line") {
+ elementParser = ememory::makeShared(m_paint);
+ } else if (child.getValue() == "polyline") {
+ elementParser = ememory::makeShared(m_paint);
+ } else if (child.getValue() == "polygon") {
+ elementParser = ememory::makeShared(m_paint);
+ } else if (child.getValue() == "text") {
+ elementParser = ememory::makeShared(m_paint);
+ } else {
+ Log.error("(l " << child.getPos() << ") node not suported : '" << child.getValue() << "' must be [g,a,path,rect,circle,ellipse,line,polyline,polygon,text]");
+ }
+ if (elementParser == null) {
+ Log.error("(l " << child.getPos() << ") error on node: '" << child.getValue() << "' allocation error or not supported ...");
+ continue;
+ }
+ if (elementParser->parseXML(child, m_transformMatrix, tmpPos) == false) {
+ Log.error("(l " << child.getPos() << ") error on node: '" << child.getValue() << "' Sub Parsing ERROR");
+ elementParser.reset();
+ continue;
+ }
+ _sizeMax.setValue(etk::max(_sizeMax.x(), tmpPos.x()),
+ etk::max(_sizeMax.y(), tmpPos.y()));
+ // add element in the system
+ m_subElementList.pushBack(elementParser);
+ }
+ return true;
+}
+
+void esvg::Group::display(int32_t _spacing) {
+ Log.debug(spacingDist(_spacing) << "Group (START) fill=" << m_paint.fill.first << "/" << m_paint.fill.second
+ << " stroke=" << m_paint.stroke.first << "/" << m_paint.stroke.second
+ << " stroke-width=" << m_paint.strokeWidth );
+ for (auto &it : m_subElementList) {
+ if (it != null) {
+ it->display(_spacing+1);
+ }
+ }
+ Log.debug(spacingDist(_spacing) << "Group (STOP)");
+}
+
+void esvg::Group::draw(esvg::Renderer& _myRenderer, mat2x3& _basicTrans, int32_t _level) {
+ Log.verbose(spacingDist(_level) << "DRAW esvg::group");
+ for (auto &it : m_subElementList) {
+ if (it != null) {
+ it->draw(_myRenderer, _basicTrans, _level+1);
+ }
+ }
+}
+
+void esvg::Group::drawShapePoints(etk::Vector>& _out,
+ int32_t _recurtionMax,
+ float _threshold,
+ mat2x3& _basicTrans,
+ int32_t _level) {
+ Log.verbose(spacingDist(_level) << "DRAW shape esvg::group");
+ for (auto &it : m_subElementList) {
+ if (it != null) {
+ it->drawShapePoints(_out, _recurtionMax, _threshold, _basicTrans, _level+1);
+ }
+ }
+}
+
diff --git a/src/org/atriasoft/esvg/Group.java b/src/org/atriasoft/esvg/Group.java
new file mode 100644
index 0000000..9f8bedb
--- /dev/null
+++ b/src/org/atriasoft/esvg/Group.java
@@ -0,0 +1,28 @@
+/** @file
+ * @author Edouard DUPIN
+ * @copyright 2011, Edouard DUPIN, all right reserved
+ * @license MPL v2.0 (see license file)
+ */
+#pragma once
+
+#include
+#include
+
+namespace esvg {
+ class Group : public esvg::Base {
+ private:
+ etk::Vector> m_subElementList; //!< sub elements ...
+ public:
+ Group(PaintState _parentPaintState);
+ ~Group();
+ bool parseXML(const exml::Element& _element, mat2x3& _parentTrans, vec2& _sizeMax) override;
+ void display(int32_t spacing) override;
+ void draw(esvg::Renderer& _myRenderer, mat2x3& _basicTrans, int32_t _level) override;
+ void drawShapePoints(etk::Vector>& _out,
+ int32_t _recurtionMax,
+ float _threshold,
+ mat2x3& _basicTrans,
+ int32_t _level=1) override;
+ };
+}
+
diff --git a/src/org/atriasoft/esvg/Line.cpp b/src/org/atriasoft/esvg/Line.cpp
new file mode 100644
index 0000000..11e1160
--- /dev/null
+++ b/src/org/atriasoft/esvg/Line.cpp
@@ -0,0 +1,139 @@
+/** @file
+ * @author Edouard DUPIN
+ * @copyright 2011, Edouard DUPIN, all right reserved
+ * @license MPL v2.0 (see license file)
+ */
+
+#include
+#include
+#include
+#include
+
+esvg::Line::Line(PaintState _parentPaintState) : esvg::Base(_parentPaintState) {
+ m_startPos.setValue(0,0);
+ m_stopPos.setValue(0,0);
+}
+
+esvg::Line::~Line() {
+
+}
+
+bool esvg::Line::parseXML(const exml::Element& _element, mat2x3& _parentTrans, vec2& _sizeMax) {
+ // line must have a minimum size...
+ m_paint.strokeWidth = 1;
+ if (_element.exist() == false) {
+ return false;
+ }
+ parseTransform(_element);
+ parsePaintAttr(_element);
+
+ // add the property of the parrent modifications ...
+ m_transformMatrix *= _parentTrans;
+
+ etk::String content = _element.attributes["x1"];
+ if (content.size() != 0) {
+ m_startPos.setX(parseLength(content));
+ }
+ content = _element.attributes["y1"];
+ if (content.size() != 0) {
+ m_startPos.setY(parseLength(content));
+ }
+ content = _element.attributes["x2"];
+ if (content.size() != 0) {
+ m_stopPos.setX(parseLength(content));
+ }
+ content = _element.attributes["y2"];
+ if (content.size() != 0) {
+ m_stopPos.setY(parseLength(content));
+ }
+ _sizeMax.setValue(etk::max(m_startPos.x(), m_stopPos.x()),
+ etk::max(m_startPos.y(), m_stopPos.y()));
+ return true;
+}
+
+void esvg::Line::display(int32_t _spacing) {
+ Log.debug(spacingDist(_spacing) << "Line " << m_startPos << " to " << m_stopPos);
+}
+
+esvg::render::Path esvg::Line::createPath() {
+ esvg::render::Path out;
+ out.clear();
+ out.moveTo(false, m_startPos);
+ out.lineTo(false, m_stopPos);
+ out.stop();
+ return out;
+}
+
+void esvg::Line::draw(esvg::Renderer& _myRenderer, mat2x3& _basicTrans, int32_t _level) {
+ Log.verbose(spacingDist(_level) << "DRAW esvg::Line");
+
+ esvg::render::Path listElement = createPath();
+
+ mat2x3 mtx = m_transformMatrix;
+ mtx *= _basicTrans;
+
+ esvg::render::PointList listPoints;
+ listPoints = listElement.generateListPoints(_level,
+ _myRenderer.getInterpolationRecurtionMax(),
+ _myRenderer.getInterpolationThreshold());
+ //listPoints.applyMatrix(mtx);
+ esvg::render::SegmentList listSegmentFill;
+ esvg::render::SegmentList listSegmentStroke;
+ esvg::render::Weight tmpFill;
+ esvg::render::Weight tmpStroke;
+ ememory::SharedPtr colorFill = esvg::render::createColor(m_paint.fill, mtx);
+ ememory::SharedPtr colorStroke;
+ if (m_paint.strokeWidth > 0.0f) {
+ colorStroke = esvg::render::createColor(m_paint.stroke, mtx);
+ }
+ // Check if we need to display background
+ // No background ...
+ // check if we need to display stroke:
+ if (colorStroke != null) {
+ listSegmentStroke.createSegmentListStroke(listPoints,
+ m_paint.strokeWidth,
+ m_paint.lineCap,
+ m_paint.lineJoin,
+ m_paint.miterLimit);
+ colorStroke->setViewPort(listSegmentStroke.getViewPort());
+ listSegmentStroke.applyMatrix(mtx);
+ // now, traverse the scanlines and find the intersections on each scanline, use non-zero rule
+ tmpStroke.generate(_myRenderer.getSize(),
+ _myRenderer.getNumberSubScanLine(),
+ listSegmentStroke);
+ }
+ // add on images:
+ _myRenderer.print(tmpFill,
+ colorFill,
+ tmpStroke,
+ colorStroke,
+ m_paint.opacity);
+ #ifdef DEBUG
+ _myRenderer.addDebugSegment(listSegmentFill);
+ _myRenderer.addDebugSegment(listSegmentStroke);
+ _myRenderer.addDebugSegment(listElement.m_debugInformation);
+ #endif
+}
+
+
+void esvg::Line::drawShapePoints(etk::Vector>& _out,
+ int32_t _recurtionMax,
+ float _threshold,
+ mat2x3& _basicTrans,
+ int32_t _level) {
+ Log.verbose(spacingDist(_level) << "DRAW Shape esvg::Line");
+ esvg::render::Path listElement = createPath();
+ mat2x3 mtx = m_transformMatrix;
+ mtx *= _basicTrans;
+ esvg::render::PointList listPoints;
+ listPoints = listElement.generateListPoints(_level, _recurtionMax, _threshold);
+ listPoints.applyMatrix(mtx);
+ for (auto &it : listPoints.m_data) {
+ etk::Vector listPoint;
+ for (auto &itDot : it) {
+ listPoint.pushBack(itDot.m_pos);
+ }
+ _out.pushBack(listPoint);
+ }
+}
+
diff --git a/src/org/atriasoft/esvg/Line.java b/src/org/atriasoft/esvg/Line.java
new file mode 100644
index 0000000..bff9baa
--- /dev/null
+++ b/src/org/atriasoft/esvg/Line.java
@@ -0,0 +1,30 @@
+/** @file
+ * @author Edouard DUPIN
+ * @copyright 2011, Edouard DUPIN, all right reserved
+ * @license MPL v2.0 (see license file)
+ */
+#pragma once
+
+#include
+
+namespace esvg {
+ class Line : public esvg::Base {
+ private:
+ vec2 m_startPos; //!< Start line position
+ vec2 m_stopPos; //!< Stop line position
+ public:
+ Line(PaintState _parentPaintState);
+ ~Line();
+ bool parseXML(const exml::Element& _element, mat2x3& _parentTrans, vec2& _sizeMax) override;
+ void display(int32_t _spacing) override;
+ void draw(esvg::Renderer& _myRenderer, mat2x3& _basicTrans, int32_t _level) override;
+ void drawShapePoints(etk::Vector>& _out,
+ int32_t _recurtionMax,
+ float _threshold,
+ mat2x3& _basicTrans,
+ int32_t _level=1) override;
+ private:
+ esvg::render::Path createPath();
+ };
+}
+
diff --git a/src/org/atriasoft/esvg/LinearGradient.cpp b/src/org/atriasoft/esvg/LinearGradient.cpp
new file mode 100644
index 0000000..96ea594
--- /dev/null
+++ b/src/org/atriasoft/esvg/LinearGradient.cpp
@@ -0,0 +1,176 @@
+/** @file
+ * @author Edouard DUPIN
+ * @copyright 2011, Edouard DUPIN, all right reserved
+ * @license MPL v2.0 (see license file)
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+esvg::LinearGradient::LinearGradient(PaintState _parentPaintState) :
+ esvg::Base(_parentPaintState),
+ m_pos1(vec2(50,50), esvg::distance_pourcent),
+ m_pos2(vec2(50,50), esvg::distance_pourcent),
+ m_unit(gradientUnits_objectBoundingBox),
+ m_spread(spreadMethod_pad) {
+
+}
+
+esvg::LinearGradient::~LinearGradient() {
+
+}
+
+
+bool esvg::LinearGradient::parseXML(const exml::Element& _element, mat2x3& _parentTrans, vec2& _sizeMax) {
+ // line must have a minimum size...
+ //m_paint.strokeWidth = 1;
+ if (_element.exist() == false) {
+ return false;
+ }
+
+ // ---------------- get unique ID ----------------
+ m_id = _element.attributes["id"];
+
+ //parseTransform(_element);
+ //parsePaintAttr(_element);
+
+ // add the property of the parrent modifications ...
+ m_transformMatrix *= _parentTrans;
+
+ etk::String contentX = _element.attributes["x1"];
+ etk::String contentY = _element.attributes["y1"];
+ if ( contentX != ""
+ && contentY != "") {
+ m_pos1.set(contentX, contentY);
+ }
+ contentX = _element.attributes["x2"];
+ contentY = _element.attributes["y2"];
+ if ( contentX != ""
+ && contentY != "") {
+ m_pos2.set(contentX, contentY);
+ }
+ contentX = _element.attributes["gradientUnits"];
+ if (contentX == "userSpaceOnUse") {
+ m_unit = gradientUnits_userSpaceOnUse;
+ } else {
+ m_unit = gradientUnits_objectBoundingBox;
+ if ( contentX.size() != 0
+ && contentX != "objectBoundingBox") {
+ Log.error("Parsing error of 'gradientUnits' ==> not suported value: '" << contentX << "' not in : {userSpaceOnUse/objectBoundingBox} use objectBoundingBox");
+ }
+ }
+ contentX = _element.attributes["spreadMethod"];
+ if (contentX == "reflect") {
+ m_spread = spreadMethod_reflect;
+ } else if (contentX == "repeat") {
+ m_spread = spreadMethod_repeat;
+ } else {
+ m_spread = spreadMethod_pad;
+ if ( contentX.size() != 0
+ && contentX != "pad") {
+ Log.error("Parsing error of 'spreadMethod' ==> not suported value: '" << contentX << "' not in : {reflect/repeate/pad} use pad");
+ }
+ }
+ // note: xlink:href is incompatible with subNode "stop"
+ m_href = _element.attributes["xlink:href"];
+ if (m_href.size() != 0) {
+ m_href = etk::String(m_href.begin()+1, m_href.end());
+ }
+ // parse all sub node :
+ for(const auto it : _element.nodes) {
+ exml::Element child = it.toElement();
+ if (child.exist() == false) {
+ // can be a comment ...
+ continue;
+ }
+ if (child.getValue() == "stop") {
+ float offset = 100;
+ etk::Color stopColor = etk::color::none;
+ etk::String content = child.attributes["offset"];
+ if (content.size()!=0) {
+ etk::Pair tmp = parseLength2(content);
+ if (tmp.second == esvg::distance_pixel) {
+ // special case ==> all time % then no type define ==> % in [0.0 .. 1.0]
+ offset = tmp.first*100.0f;
+ } else if (tmp.second != esvg::distance_pourcent) {
+ Log.error("offset : " << content << " res=" << tmp.first << "," << tmp.second << " Not support other than pourcent %");
+ } else {
+ offset = tmp.first;
+ }
+ }
+ content = child.attributes["stop-color"];
+ if (content.size()!=0) {
+ stopColor = parseColor(content).first;
+ Log.verbose(" color : '" << content << "' == > " << stopColor);
+ }
+ content = child.attributes["stop-opacity"];
+ if (content.size()!=0) {
+ float opacity = parseLength(content);
+ opacity = etk::avg(0.0f, opacity, 1.0f);
+ stopColor.setA(opacity);
+ Log.verbose(" opacity : '" << content << "' == > " << stopColor);
+ }
+ m_data.pushBack(etk::Pair>(offset, stopColor));
+ } else {
+ Log.error("(l " << child.getPos() << ") node not suported : '" << child.getValue() << "' must be [stop]");
+ }
+ }
+ if (m_data.size() != 0) {
+ if (m_href != "") {
+ Log.error("(l " << _element.getPos() << ") node can not have an xlink:href element with sub node named: stop ==> removing href");
+ m_href = "";
+ }
+ }
+ return true;
+}
+
+void esvg::LinearGradient::display(int32_t _spacing) {
+ Log.debug(spacingDist(_spacing) << "LinearGradient " << m_pos1 << " to " << m_pos2);
+ for (auto &it : m_data) {
+ Log.debug(spacingDist(_spacing+1) << "STOP: offset=" << it.first << " color=" << it.second);
+ }
+}
+
+void esvg::LinearGradient::draw(esvg::Renderer& _myRenderer, mat2x3& _basicTrans, int32_t _level) {
+ Log.verbose(spacingDist(_level) << "DRAW esvg::LinearGradient");
+}
+
+const esvg::Dimension& esvg::LinearGradient::getPosition1() {
+ return m_pos1;
+}
+
+const esvg::Dimension& esvg::LinearGradient::getPosition2() {
+ return m_pos2;
+}
+
+const etk::Vector>>& esvg::LinearGradient::getColors(esvg::Document* _document) {
+ if (m_href == "") {
+ return m_data;
+ }
+ if (_document == null) {
+ Log.error("Get null input for document");
+ return m_data;
+ }
+ ememory::SharedPtr base = _document->getReference(m_href);
+ if (base == null) {
+ Log.error("Can not get base : '" << m_href << "'");
+ return m_data;
+ }
+ ememory::SharedPtr gradientR = ememory::dynamicPointerCast(base);
+ if (gradientR == null) {
+ ememory::SharedPtr gradientL = ememory::dynamicPointerCast(base);
+ if (gradientL == null) {
+ Log.error("Can not cast in a linear/radial gradient: '" << m_href << "' ==> wrong type");
+ return m_data;
+ }
+ return gradientL->getColors(_document);
+ }
+ return gradientR->getColors(_document);
+}
+
+
+
diff --git a/src/org/atriasoft/esvg/LinearGradient.java b/src/org/atriasoft/esvg/LinearGradient.java
new file mode 100644
index 0000000..84d4630
--- /dev/null
+++ b/src/org/atriasoft/esvg/LinearGradient.java
@@ -0,0 +1,36 @@
+/** @file
+ * @author Edouard DUPIN
+ * @copyright 2011, Edouard DUPIN, all right reserved
+ * @license MPL v2.0 (see license file)
+ */
+#pragma once
+
+#include
+#include
+#include
+
+namespace esvg {
+ class Document;
+ class LinearGradient : public esvg::Base {
+ private:
+ esvg::Dimension m_pos1; //!< gradient position x1 y1
+ esvg::Dimension m_pos2; //!< gradient position x2 y2
+ public:
+ enum gradientUnits m_unit;
+ enum spreadMethod m_spread;
+ private:
+ etk::String m_href; //!< in case of using a single gradient in multiple gradient, the gradient is store in an other element...
+ etk::Vector>> m_data; //!< incompatible with href
+ public:
+ LinearGradient(PaintState _parentPaintState);
+ ~LinearGradient();
+ virtual bool parseXML(const exml::Element& _element, mat2x3& _parentTrans, vec2& _sizeMax);
+ virtual void display(int32_t _spacing);
+ virtual void draw(esvg::Renderer& _myRenderer, mat2x3& _basicTrans, int32_t _level);
+ public:
+ const esvg::Dimension& getPosition1();
+ const esvg::Dimension& getPosition2();
+ const etk::Vector>>& getColors(esvg::Document* _document);
+ };
+}
+
diff --git a/src/org/atriasoft/esvg/Path.cpp b/src/org/atriasoft/esvg/Path.cpp
new file mode 100644
index 0000000..b826503
--- /dev/null
+++ b/src/org/atriasoft/esvg/Path.cpp
@@ -0,0 +1,349 @@
+/** @file
+ * @author Edouard DUPIN
+ * @copyright 2011, Edouard DUPIN, all right reserved
+ * @license MPL v2.0 (see license file)
+ */
+
+#include
+#include
+#include
+#include
+
+esvg::Path::Path(PaintState _parentPaintState) : esvg::Base(_parentPaintState) {
+
+}
+
+esvg::Path::~Path() {
+
+}
+
+
+// return the next char position ... (after 'X' or NULL)
+const char * extractCmd(const char* _input, char& _cmd, etk::Vector& _outputList) {
+ if (*_input == '\0') {
+ return null;
+ }
+ _outputList.clear();
+ _cmd = '\0';
+ const char * outputPointer = null;
+ if (!( ( _input[0] <= 'Z'
+ && _input[0] >= 'A')
+ || ( _input[0] <= 'z'
+ && _input[0] >= 'a') ) ) {
+ Log.error("Error in the SVG Path : \"" << _input << "\"");
+ return null;
+ }
+ _cmd = _input[0];
+ Log.verbose("Find command : " << _cmd);
+ if (_input[1] == '\0') {
+ return &_input[1];
+ }
+ int32_t iii=1;
+ // extract every float separated by a ' ' or a ','
+ float element;
+ char spacer[10];
+ int32_t nbElementRead;
+ while( sscanf(&_input[iii], "%1[, ]%f%n", spacer, &element, &nbElementRead) == 2
+ || sscanf(&_input[iii], "%f%n", &element, &nbElementRead) == 1) {
+ Log.verbose("Find element : " << element);
+ _outputList.pushBack(element);
+ iii += nbElementRead;
+ }
+ outputPointer = &_input[iii];
+ while(*outputPointer!= '\0' && *outputPointer == ' ') {
+ outputPointer++;
+ }
+ //outputPointer++;
+ return outputPointer;
+}
+etk::String cleanBadSpaces(const etk::String& _input) {
+ etk::String out;
+ bool haveSpace = false;
+ for (auto &it : _input) {
+ if ( it == ' '
+ || it == '\t'
+ || it == '\t'
+ || it == '\r') {
+ haveSpace = true;
+ } else {
+ if (haveSpace == true) {
+ haveSpace = false;
+ out += ' ';
+ }
+ out += it;
+ }
+ }
+ return out;
+}
+
+bool esvg::Path::parseXML(const exml::Element& _element, mat2x3& _parentTrans, vec2& _sizeMax) {
+ if (_element.exist() == false) {
+ return false;
+ }
+ parseTransform(_element);
+ parsePaintAttr(_element);
+
+ // add the property of the parrent modifications ...
+ m_transformMatrix *= _parentTrans;
+
+
+ etk::String elementXML1 = _element.attributes["d"];
+ if (elementXML1.size() == 0) {
+ Log.warning("(l "<<_element.getPos()<<") path: missing 'd' attribute or empty");
+ return false;
+ }
+ Log.verbose("Parse Path : \"" << elementXML1 << "\"");
+
+ char command;
+ etk::Vector listDot;
+ elementXML1 = cleanBadSpaces(elementXML1);
+ const char* elementXML = elementXML1.c_str();
+
+ for( const char *sss=extractCmd(elementXML, command, listDot);
+ sss != null;
+ sss=extractCmd(sss, command, listDot) ) {
+ bool relative = false;
+ switch(command) {
+ case 'm': // Move to (relative)
+ relative = true;
+ case 'M': // Move to (absolute)
+ // 2 Elements ...
+ if(listDot.size()%2 != 0) {
+ Log.warning("the PATH command "<< command << " has not the good number of element = " << listDot.size() );
+ break;
+ }
+ if (listDot.size() >= 2) {
+ m_listElement.moveTo(relative,
+ vec2(listDot[0], listDot[1]));
+ }
+ for (size_t iii=2; iii colorFill = esvg::render::createColor(m_paint.fill, mtx);
+ ememory::SharedPtr colorStroke;
+ if (m_paint.strokeWidth > 0.0f) {
+ colorStroke = esvg::render::createColor(m_paint.stroke, mtx);
+ }
+ // Check if we need to display background
+ if (colorFill != null) {
+ listSegmentFill.createSegmentList(listPoints);
+ colorFill->setViewPort(listSegmentFill.getViewPort());
+ listSegmentFill.applyMatrix(mtx);
+ // now, traverse the scanlines and find the intersections on each scanline, use non-zero rule
+ tmpFill.generate(_myRenderer.getSize(), _myRenderer.getNumberSubScanLine(), listSegmentFill);
+ }
+ // check if we need to display stroke:
+ if (colorStroke != null) {
+ listSegmentStroke.createSegmentListStroke(listPoints,
+ m_paint.strokeWidth,
+ m_paint.lineCap,
+ m_paint.lineJoin,
+ m_paint.miterLimit);
+ colorStroke->setViewPort(listSegmentStroke.getViewPort());
+ listSegmentStroke.applyMatrix(mtx);
+ // now, traverse the scanlines and find the intersections on each scanline, use non-zero rule
+ tmpStroke.generate(_myRenderer.getSize(), _myRenderer.getNumberSubScanLine(), listSegmentStroke);
+ }
+ // add on images:
+ _myRenderer.print(tmpFill,
+ colorFill,
+ tmpStroke,
+ colorStroke,
+ m_paint.opacity);
+ #ifdef DEBUG
+ _myRenderer.addDebugSegment(listSegmentFill);
+ _myRenderer.addDebugSegment(listSegmentStroke);
+ m_listElement.m_debugInformation.applyMatrix(mtx);
+ _myRenderer.addDebugSegment(m_listElement.m_debugInformation);
+ #endif
+}
+
+
+void esvg::Path::drawShapePoints(etk::Vector>& _out,
+ int32_t _recurtionMax,
+ float _threshold,
+ mat2x3& _basicTrans,
+ int32_t _level) {
+ Log.verbose(spacingDist(_level) << "DRAW Shape esvg::Path");
+
+ mat2x3 mtx = m_transformMatrix;
+ mtx *= _basicTrans;
+
+ esvg::render::PointList listPoints;
+ listPoints = m_listElement.generateListPoints(_level, _recurtionMax, _threshold);
+ listPoints.applyMatrix(mtx);
+ for (auto &it : listPoints.m_data) {
+ etk::Vector listPoint;
+ for (auto &itDot : it) {
+ listPoint.pushBack(itDot.m_pos);
+ }
+ _out.pushBack(listPoint);
+ }
+}
+
diff --git a/src/org/atriasoft/esvg/Path.java b/src/org/atriasoft/esvg/Path.java
new file mode 100644
index 0000000..2427089
--- /dev/null
+++ b/src/org/atriasoft/esvg/Path.java
@@ -0,0 +1,28 @@
+/** @file
+ * @author Edouard DUPIN
+ * @copyright 2011, Edouard DUPIN, all right reserved
+ * @license MPL v2.0 (see license file)
+ */
+#pragma once
+
+#include
+#include
+
+namespace esvg {
+ class Path : public esvg::Base {
+ public:
+ esvg::render::Path m_listElement;
+ public:
+ Path(PaintState _parentPaintState);
+ ~Path();
+ bool parseXML(const exml::Element& _element, mat2x3& _parentTrans, vec2& _sizeMax) override;
+ void display(int32_t _spacing) override;
+ void draw(esvg::Renderer& _myRenderer, mat2x3& _basicTrans, int32_t _level) override;
+ void drawShapePoints(etk::Vector>& _out,
+ int32_t _recurtionMax,
+ float _threshold,
+ mat2x3& _basicTrans,
+ int32_t _level=1) override;
+ };
+}
+
diff --git a/src/org/atriasoft/esvg/Polygon.cpp b/src/org/atriasoft/esvg/Polygon.cpp
new file mode 100644
index 0000000..e1bc214
--- /dev/null
+++ b/src/org/atriasoft/esvg/Polygon.cpp
@@ -0,0 +1,153 @@
+/** @file
+ * @author Edouard DUPIN
+ * @copyright 2011, Edouard DUPIN, all right reserved
+ * @license MPL v2.0 (see license file)
+ */
+
+#include
+#include
+#include
+#include
+
+esvg::Polygon::Polygon(PaintState parentPaintState) : esvg::Base(parentPaintState) {
+
+}
+
+esvg::Polygon::~Polygon() {
+
+}
+
+bool esvg::Polygon::parseXML(const exml::Element& _element, mat2x3& _parentTrans, vec2& _sizeMax) {
+ if (_element.exist() == false) {
+ return false;
+ }
+ parseTransform(_element);
+ parsePaintAttr(_element);
+
+ Log.verbose("parsed P1. trans: " << m_transformMatrix);
+
+ // add the property of the parrent modifications ...
+ m_transformMatrix *= _parentTrans;
+
+ Log.verbose("parsed P2. trans: " << m_transformMatrix);
+
+ const etk::String sss1 = _element.attributes["points"];
+ if (sss1.size() == 0) {
+ Log.error("(l "/*<<_element->Pos()*/<<") polygon: missing points attribute");
+ return false;
+ }
+ const char * sss = sss1.c_str();
+ _sizeMax.setValue(0,0);
+ Log.verbose("Parse polygon : \"" << sss << "\"");
+ while ('\0' != sss[0]) {
+ vec2 pos(0,0);
+ int32_t n;
+ if (sscanf(sss, "%f,%f%n", &pos.m_floats[0], &pos.m_floats[1], &n) == 2) {
+ m_listPoint.pushBack(pos);
+ sss += n;
+ _sizeMax.setValue(etk::max(_sizeMax.x(), pos.x()),
+ etk::max(_sizeMax.y(), pos.y()));
+ if(sss[0] == ' ' || sss[0] == ',') {
+ sss++;
+ }
+ } else {
+ break;
+ }
+ }
+ return true;
+}
+
+void esvg::Polygon::display(int32_t _spacing) {
+ Log.debug(spacingDist(_spacing) << "Polygon nbPoint=" << m_listPoint.size());
+}
+
+esvg::render::Path esvg::Polygon::createPath() {
+ esvg::render::Path out;
+ out.moveTo(false, m_listPoint[0]);
+ for(size_t iii=1; iii< m_listPoint.size(); iii++) {
+ out.lineTo(false, m_listPoint[iii]);
+ }
+ out.close();
+ return out;
+}
+
+void esvg::Polygon::draw(esvg::Renderer& _myRenderer, mat2x3& _basicTrans, int32_t _level) {
+ Log.verbose(spacingDist(_level) << "DRAW esvg::Polygon");
+
+ esvg::render::Path listElement = createPath();
+
+ mat2x3 mtx = m_transformMatrix;
+ mtx *= _basicTrans;
+
+ esvg::render::PointList listPoints;
+ listPoints = listElement.generateListPoints(_level,
+ _myRenderer.getInterpolationRecurtionMax(),
+ _myRenderer.getInterpolationThreshold());
+ //listPoints.applyMatrix(mtx);
+ esvg::render::SegmentList listSegmentFill;
+ esvg::render::SegmentList listSegmentStroke;
+ esvg::render::Weight tmpFill;
+ esvg::render::Weight tmpStroke;
+ ememory::SharedPtr colorFill = esvg::render::createColor(m_paint.fill, mtx);
+ ememory::SharedPtr colorStroke;
+ if (m_paint.strokeWidth > 0.0f) {
+ colorStroke = esvg::render::createColor(m_paint.stroke, mtx);
+ }
+ // Check if we need to display background
+ if (colorFill != null) {
+ listSegmentFill.createSegmentList(listPoints);
+ colorFill->setViewPort(listSegmentFill.getViewPort());
+ listSegmentFill.applyMatrix(mtx);
+ // now, traverse the scanlines and find the intersections on each scanline, use non-zero rule
+ tmpFill.generate(_myRenderer.getSize(),
+ _myRenderer.getNumberSubScanLine(),
+ listSegmentFill);
+ }
+ // check if we need to display stroke:
+ if (colorStroke != null) {
+ listSegmentStroke.createSegmentListStroke(listPoints,
+ m_paint.strokeWidth,
+ m_paint.lineCap,
+ m_paint.lineJoin,
+ m_paint.miterLimit);
+ colorStroke->setViewPort(listSegmentStroke.getViewPort());
+ listSegmentStroke.applyMatrix(mtx);
+ // now, traverse the scanlines and find the intersections on each scanline, use non-zero rule
+ tmpStroke.generate(_myRenderer.getSize(),
+ _myRenderer.getNumberSubScanLine(),
+ listSegmentStroke);
+ }
+ // add on images:
+ _myRenderer.print(tmpFill,
+ colorFill,
+ tmpStroke,
+ colorStroke,
+ m_paint.opacity);
+ #ifdef DEBUG
+ _myRenderer.addDebugSegment(listSegmentFill);
+ _myRenderer.addDebugSegment(listSegmentStroke);
+ #endif
+}
+
+
+void esvg::Polygon::drawShapePoints(etk::Vector>& _out,
+ int32_t _recurtionMax,
+ float _threshold,
+ mat2x3& _basicTrans,
+ int32_t _level) {
+ Log.verbose(spacingDist(_level) << "DRAW Shape esvg::Polygon");
+ esvg::render::Path listElement = createPath();
+ mat2x3 mtx = m_transformMatrix;
+ mtx *= _basicTrans;
+ esvg::render::PointList listPoints;
+ listPoints = listElement.generateListPoints(_level, _recurtionMax, _threshold);
+ listPoints.applyMatrix(mtx);
+ for (auto &it : listPoints.m_data) {
+ etk::Vector listPoint;
+ for (auto &itDot : it) {
+ listPoint.pushBack(itDot.m_pos);
+ }
+ _out.pushBack(listPoint);
+ }
+}
+
diff --git a/src/org/atriasoft/esvg/Polygon.java b/src/org/atriasoft/esvg/Polygon.java
new file mode 100644
index 0000000..e6223a6
--- /dev/null
+++ b/src/org/atriasoft/esvg/Polygon.java
@@ -0,0 +1,37 @@
+/** @file
+ * @author Edouard DUPIN
+ * @copyright 2011, Edouard DUPIN, all right reserved
+ * @license MPL v2.0 (see license file)
+ */
+#pragma once
+
+#include
+#include
+
+namespace esvg {
+ /*
+ enum polygonMode {
+ polygoneModeNonZero,
+ polygoneModeEvenOdd
+ };
+ */
+ class Polygon : public esvg::Base {
+ private:
+ etk::Vector m_listPoint; //!< list of all point of the polygone
+ //enum esvg::polygonMode m_diplayMode; //!< polygone specific display mode
+ public:
+ Polygon(PaintState parentPaintState);
+ ~Polygon();
+ bool parseXML(const exml::Element& _element, mat2x3& _parentTrans, vec2& _sizeMax) override;
+ void display(int32_t _spacing) override;
+ void draw(esvg::Renderer& _myRenderer, mat2x3& _basicTrans, int32_t _level) override;
+ void drawShapePoints(etk::Vector>& _out,
+ int32_t _recurtionMax,
+ float _threshold,
+ mat2x3& _basicTrans,
+ int32_t _level=1) override;
+ private:
+ esvg::render::Path createPath();
+ };
+}
+
diff --git a/src/org/atriasoft/esvg/Polyline.cpp b/src/org/atriasoft/esvg/Polyline.cpp
new file mode 100644
index 0000000..1f4c6f4
--- /dev/null
+++ b/src/org/atriasoft/esvg/Polyline.cpp
@@ -0,0 +1,149 @@
+/** @file
+ * @author Edouard DUPIN
+ * @copyright 2011, Edouard DUPIN, all right reserved
+ * @license MPL v2.0 (see license file)
+ */
+
+#include
+#include
+#include
+#include
+
+esvg::Polyline::Polyline(PaintState _parentPaintState) : esvg::Base(_parentPaintState) {
+
+}
+
+esvg::Polyline::~Polyline() {
+
+}
+
+bool esvg::Polyline::parseXML(const exml::Element& _element, mat2x3& _parentTrans, vec2& _sizeMax) {
+ // line must have a minimum size...
+ m_paint.strokeWidth = 1;
+ if (_element.exist() == false) {
+ return false;
+ }
+ parseTransform(_element);
+ parsePaintAttr(_element);
+
+ // add the property of the parrent modifications ...
+ m_transformMatrix *= _parentTrans;
+
+ etk::String sss1 = _element.attributes["points"];
+ if (sss1.size() == 0) {
+ Log.error("(l "<<_element.getPos()<<") polyline: missing points attribute");
+ return false;
+ }
+ _sizeMax.setValue(0,0);
+ Log.verbose("Parse polyline : \"" << sss1 << "\"");
+ const char* sss = sss1.c_str();
+ while ('\0' != sss[0]) {
+ vec2 pos;
+ int32_t n;
+ if (sscanf(sss, "%f,%f %n", &pos.m_floats[0], &pos.m_floats[1], &n) == 2) {
+ m_listPoint.pushBack(pos);
+ _sizeMax.setValue(etk::max(_sizeMax.x(), pos.x()),
+ etk::max(_sizeMax.y(), pos.y()));
+ sss += n;
+ } else {
+ break;
+ }
+ }
+ return true;
+}
+
+void esvg::Polyline::display(int32_t _spacing) {
+ Log.debug(spacingDist(_spacing) << "Polyline nbPoint=" << m_listPoint.size());
+}
+
+
+esvg::render::Path esvg::Polyline::createPath() {
+ esvg::render::Path out;
+ out.clear();
+ out.moveTo(false, m_listPoint[0]);
+ for(size_t iii=1; iii< m_listPoint.size(); iii++) {
+ out.lineTo(false, m_listPoint[iii]);
+ }
+ out.stop();
+ return out;
+}
+
+void esvg::Polyline::draw(esvg::Renderer& _myRenderer, mat2x3& _basicTrans, int32_t _level) {
+ Log.verbose(spacingDist(_level) << "DRAW esvg::Polyline");
+
+ esvg::render::Path listElement = createPath();
+
+ mat2x3 mtx = m_transformMatrix;
+ mtx *= _basicTrans;
+
+ esvg::render::PointList listPoints;
+ listPoints = listElement.generateListPoints(_level,
+ _myRenderer.getInterpolationRecurtionMax(),
+ _myRenderer.getInterpolationThreshold());
+ //listPoints.applyMatrix(mtx);
+ esvg::render::SegmentList listSegmentFill;
+ esvg::render::SegmentList listSegmentStroke;
+ esvg::render::Weight tmpFill;
+ esvg::render::Weight tmpStroke;
+ ememory::SharedPtr colorFill = esvg::render::createColor(m_paint.fill, mtx);
+ ememory::SharedPtr colorStroke;
+ if (m_paint.strokeWidth > 0.0f) {
+ colorStroke = esvg::render::createColor(m_paint.stroke, mtx);
+ }
+ // Check if we need to display background
+ if (colorFill != null) {
+ listSegmentFill.createSegmentList(listPoints);
+ colorFill->setViewPort(listSegmentFill.getViewPort());
+ listSegmentFill.applyMatrix(mtx);
+ // now, traverse the scanlines and find the intersections on each scanline, use non-zero rule
+ tmpFill.generate(_myRenderer.getSize(),
+ _myRenderer.getNumberSubScanLine(),
+ listSegmentFill);
+ }
+ // check if we need to display stroke:
+ if (colorStroke != null) {
+ listSegmentStroke.createSegmentListStroke(listPoints,
+ m_paint.strokeWidth,
+ m_paint.lineCap,
+ m_paint.lineJoin,
+ m_paint.miterLimit);
+ colorStroke->setViewPort(listSegmentStroke.getViewPort());
+ listSegmentStroke.applyMatrix(mtx);
+ // now, traverse the scanlines and find the intersections on each scanline, use non-zero rule
+ tmpStroke.generate(_myRenderer.getSize(),
+ _myRenderer.getNumberSubScanLine(),
+ listSegmentStroke);
+ }
+ // add on images:
+ _myRenderer.print(tmpFill,
+ colorFill,
+ tmpStroke,
+ colorStroke,
+ m_paint.opacity);
+ #ifdef DEBUG
+ _myRenderer.addDebugSegment(listSegmentFill);
+ _myRenderer.addDebugSegment(listSegmentStroke);
+ #endif
+}
+
+
+void esvg::Polyline::drawShapePoints(etk::Vector>& _out,
+ int32_t _recurtionMax,
+ float _threshold,
+ mat2x3& _basicTrans,
+ int32_t _level) {
+ Log.verbose(spacingDist(_level) << "DRAW Shape esvg::Polyline");
+ esvg::render::Path listElement = createPath();
+ mat2x3 mtx = m_transformMatrix;
+ mtx *= _basicTrans;
+ esvg::render::PointList listPoints;
+ listPoints = listElement.generateListPoints(_level, _recurtionMax, _threshold);
+ listPoints.applyMatrix(mtx);
+ for (auto &it : listPoints.m_data) {
+ etk::Vector listPoint;
+ for (auto &itDot : it) {
+ listPoint.pushBack(itDot.m_pos);
+ }
+ _out.pushBack(listPoint);
+ }
+}
diff --git a/src/org/atriasoft/esvg/Polyline.java b/src/org/atriasoft/esvg/Polyline.java
new file mode 100644
index 0000000..844202f
--- /dev/null
+++ b/src/org/atriasoft/esvg/Polyline.java
@@ -0,0 +1,30 @@
+/** @file
+ * @author Edouard DUPIN
+ * @copyright 2011, Edouard DUPIN, all right reserved
+ * @license MPL v2.0 (see license file)
+ */
+#pragma once
+
+#include
+#include
+
+namespace esvg {
+ class Polyline : public esvg::Base {
+ private:
+ etk::Vector m_listPoint; //!< list of all point of the polyline
+ public:
+ Polyline(PaintState _parentPaintState);
+ ~Polyline();
+ bool parseXML(const exml::Element& _element, mat2x3& _parentTrans, vec2& _sizeMax) override;
+ void display(int32_t _spacing) override;
+ void draw(esvg::Renderer& _myRenderer, mat2x3& _basicTrans, int32_t _level) override;
+ void drawShapePoints(etk::Vector>& _out,
+ int32_t _recurtionMax,
+ float _threshold,
+ mat2x3& _basicTrans,
+ int32_t _level=1) override;
+ private:
+ esvg::render::Path createPath();
+ };
+}
+
diff --git a/src/org/atriasoft/esvg/RadialGradient.cpp b/src/org/atriasoft/esvg/RadialGradient.cpp
new file mode 100644
index 0000000..17858bd
--- /dev/null
+++ b/src/org/atriasoft/esvg/RadialGradient.cpp
@@ -0,0 +1,185 @@
+/** @file
+ * @author Edouard DUPIN
+ * @copyright 2011, Edouard DUPIN, all right reserved
+ * @license MPL v2.0 (see license file)
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+esvg::RadialGradient::RadialGradient(PaintState _parentPaintState) :
+ esvg::Base(_parentPaintState),
+ m_center(vec2(50,50), esvg::distance_pourcent),
+ m_radius(50, esvg::distance_pourcent),
+ m_focal(vec2(50,50), esvg::distance_pourcent),
+ m_unit(gradientUnits_objectBoundingBox),
+ m_spread(spreadMethod_pad) {
+
+}
+
+esvg::RadialGradient::~RadialGradient() {
+
+}
+
+
+bool esvg::RadialGradient::parseXML(const exml::Element& _element, mat2x3& _parentTrans, vec2& _sizeMax) {
+ // line must have a minimum size...
+ //m_paint.strokeWidth = 1;
+ if (_element.exist() == false) {
+ return false;
+ }
+
+ // ---------------- get unique ID ----------------
+ m_id = _element.attributes["id"];
+
+ //parseTransform(_element);
+ //parsePaintAttr(_element);
+
+ // add the property of the parrent modifications ...
+ m_transformMatrix *= _parentTrans;
+
+ etk::String contentX = _element.attributes["cx"];
+ etk::String contentY = _element.attributes["cy"];
+ if ( contentX != ""
+ && contentY != "") {
+ m_center.set(contentX, contentY);
+ }
+ contentX = _element.attributes["r"];
+ if (contentX != "") {
+ m_radius.set(contentX);
+ }
+ contentX = _element.attributes["fx"];
+ contentY = _element.attributes["fy"];
+ if ( contentX != ""
+ && contentY != "") {
+ m_focal.set(contentX, contentY);
+ }
+ contentX = _element.attributes["gradientUnits"];
+ if (contentX == "userSpaceOnUse") {
+ m_unit = gradientUnits_userSpaceOnUse;
+ } else {
+ m_unit = gradientUnits_objectBoundingBox;
+ if ( contentX.size() != 0
+ && contentX != "objectBoundingBox") {
+ Log.error("Parsing error of 'gradientUnits' ==> not suported value: '" << contentX << "' not in : {userSpaceOnUse/objectBoundingBox} use objectBoundingBox");
+ }
+ }
+ contentX = _element.attributes["spreadMethod"];
+ if (contentX == "reflect") {
+ m_spread = spreadMethod_reflect;
+ } else if (contentX == "repeat") {
+ m_spread = spreadMethod_repeat;
+ } else {
+ m_spread = spreadMethod_pad;
+ if ( contentX.size() != 0
+ && contentX != "pad") {
+ Log.error("Parsing error of 'spreadMethod' ==> not suported value: '" << contentX << "' not in : {reflect/repeate/pad} use pad");
+ }
+ }
+ // note: xlink:href is incompatible with subNode "stop"
+ m_href = _element.attributes["xlink:href"];
+ if (m_href.size() != 0) {
+ m_href = etk::String(m_href.begin()+1, m_href.end());
+ }
+ // parse all sub node :
+ for(auto it : _element.nodes) {
+ exml::Element child = it.toElement();
+ if (child.exist() == false) {
+ // can be a comment ...
+ continue;
+ }
+ if (child.getValue() == "stop") {
+ float offset = 100;
+ etk::Color stopColor = etk::color::none;
+ etk::String content = child.attributes["offset"];
+ if (content.size()!=0) {
+ etk::Pair tmp = parseLength2(content);
+ if (tmp.second == esvg::distance_pixel) {
+ // special case ==> all time % then no type define ==> % in [0.0 .. 1.0]
+ offset = tmp.first*100.0f;
+ } else if (tmp.second != esvg::distance_pourcent) {
+ Log.error("offset : " << content << " res=" << tmp.first << "," << tmp.second << " Not support other than pourcent %");
+ } else {
+ offset = tmp.first;
+ }
+ }
+ content = child.attributes["stop-color"];
+ if (content.size()!=0) {
+ stopColor = parseColor(content).first;
+ Log.verbose(" color : \"" << content << "\" == > " << stopColor);
+ }
+ content = child.attributes["stop-opacity"];
+ if (content.size()!=0) {
+ float opacity = parseLength(content);
+ opacity = etk::avg(0.0f, opacity, 1.0f);
+ stopColor.setA(opacity);
+ Log.verbose(" opacity : '" << content << "' == > " << stopColor);
+ }
+ m_data.pushBack(etk::Pair>(offset, stopColor));
+ } else {
+ Log.error("(l " << child.getPos() << ") node not suported : '" << child.getValue() << "' must be [stop]");
+ }
+ }
+ if (m_data.size() != 0) {
+ if (m_href != "") {
+ Log.error("(l " << _element.getPos() << ") node can not have an xlink:href element with sub node named: stop ==> removing href");
+ m_href = "";
+ }
+ }
+ return true;
+}
+
+void esvg::RadialGradient::display(int32_t _spacing) {
+ Log.debug(spacingDist(_spacing) << "RadialGradient center=" << m_center << " focal=" << m_focal << " radius=" << m_radius);
+ for (auto &it : m_data) {
+ Log.debug(spacingDist(_spacing+1) << "STOP: offset=" << it.first << " color=" << it.second);
+ }
+}
+
+void esvg::RadialGradient::draw(esvg::Renderer& _myRenderer, mat2x3& _basicTrans, int32_t _level) {
+ Log.verbose(spacingDist(_level) << "DRAW esvg::RadialGradient");
+}
+
+const esvg::Dimension& esvg::RadialGradient::getCenter() {
+ return m_center;
+}
+
+const esvg::Dimension& esvg::RadialGradient::getFocal() {
+ return m_focal;
+}
+
+const esvg::Dimension1D& esvg::RadialGradient::getRadius() {
+ return m_radius;
+}
+
+const etk::Vector>>& esvg::RadialGradient::getColors(esvg::Document* _document) {
+ if (m_href == "") {
+ return m_data;
+ }
+ if (_document == null) {
+ Log.error("Get null input for document");
+ return m_data;
+ }
+ ememory::SharedPtr base = _document->getReference(m_href);
+ if (base == null) {
+ Log.error("Can not get base : '" << m_href << "'");
+ return m_data;
+ }
+ ememory::SharedPtr gradientR = ememory::dynamicPointerCast(base);
+ if (gradientR == null) {
+ ememory::SharedPtr gradientL = ememory::dynamicPointerCast(base);
+ if (gradientL == null) {
+ Log.error("Can not cast in a linear/radial gradient: '" << m_href << "' ==> wrong type");
+ return m_data;
+ }
+ return gradientL->getColors(_document);
+ }
+ return gradientR->getColors(_document);
+}
+
+
+
diff --git a/src/org/atriasoft/esvg/RadialGradient.java b/src/org/atriasoft/esvg/RadialGradient.java
new file mode 100644
index 0000000..05f1caf
--- /dev/null
+++ b/src/org/atriasoft/esvg/RadialGradient.java
@@ -0,0 +1,38 @@
+/** @file
+ * @author Edouard DUPIN
+ * @copyright 2011, Edouard DUPIN, all right reserved
+ * @license MPL v2.0 (see license file)
+ */
+#pragma once
+
+#include
+#include
+#include
+
+namespace esvg {
+ class Document;
+ class RadialGradient : public esvg::Base {
+ private:
+ esvg::Dimension m_center; //!< gradient position cx cy
+ esvg::Dimension1D m_radius; //!< Radius of the gradient
+ esvg::Dimension m_focal; //!< gradient Focal fx fy
+ public:
+ enum gradientUnits m_unit;
+ enum spreadMethod m_spread;
+ private:
+ etk::String m_href; //!< in case of using a single gradient in multiple gradient, the gradient is store in an other element...
+ etk::Vector>> m_data; //!< incompatible with href
+ public:
+ RadialGradient(PaintState _parentPaintState);
+ ~RadialGradient();
+ virtual bool parseXML(const exml::Element& _element, mat2x3& _parentTrans, vec2& _sizeMax);
+ virtual void display(int32_t _spacing);
+ virtual void draw(esvg::Renderer& _myRenderer, mat2x3& _basicTrans, int32_t _level);
+ public:
+ const esvg::Dimension& getCenter();
+ const esvg::Dimension& getFocal();
+ const esvg::Dimension1D& getRadius();
+ const etk::Vector>>& getColors(esvg::Document* _document);
+ };
+}
+
diff --git a/src/org/atriasoft/esvg/Rectangle.cpp b/src/org/atriasoft/esvg/Rectangle.cpp
new file mode 100644
index 0000000..de695d6
--- /dev/null
+++ b/src/org/atriasoft/esvg/Rectangle.cpp
@@ -0,0 +1,166 @@
+/** @file
+ * @author Edouard DUPIN
+ * @copyright 2011, Edouard DUPIN, all right reserved
+ * @license MPL v2.0 (see license file)
+ */
+
+#include
+#include
+#include
+#include
+
+esvg::Rectangle::Rectangle(PaintState _parentPaintState) : esvg::Base(_parentPaintState) {
+ m_position.setValue(0,0);
+ m_size.setValue(0,0);
+ m_roundedCorner.setValue(0,0);
+}
+
+esvg::Rectangle::~Rectangle() {
+
+}
+
+bool esvg::Rectangle::parseXML(const exml::Element& _element, mat2x3& _parentTrans, vec2& _sizeMax) {
+ if (_element.exist() == false) {
+ return false;
+ }
+ m_position.setValue(0.0f, 0.0f);
+ m_size.setValue(0.0f, 0.0f);
+ m_roundedCorner.setValue(0.0f, 0.0f);
+
+ parseTransform(_element);
+ parsePaintAttr(_element);
+
+ // add the property of the parrent modifications ...
+ m_transformMatrix *= _parentTrans;
+
+ parsePosition(_element, m_position, m_size);
+
+ etk::String content = _element.attributes["rx"];
+ if (content.size()!=0) {
+ m_roundedCorner.setX(parseLength(content));
+ }
+ content = _element.attributes["ry"];
+ if (content.size()!=0) {
+ m_roundedCorner.setY(parseLength(content));
+ }
+ _sizeMax.setValue(m_position.x() + m_size.x() + m_paint.strokeWidth,
+ m_position.y() + m_size.y() + m_paint.strokeWidth);
+ return true;
+}
+
+void esvg::Rectangle::display(int32_t _spacing) {
+ Log.debug(spacingDist(_spacing) << "Rectangle : pos=" << m_position << " size=" << m_size << " corner=" << m_roundedCorner);
+}
+
+esvg::render::Path esvg::Rectangle::createPath() {
+ esvg::render::Path out;
+ out.clear();
+ if ( m_roundedCorner.x() == 0.0f
+ || m_roundedCorner.y() == 0.0f) {
+ out.moveTo(false, m_position);
+ out.lineToH(true, m_size.x());
+ out.lineToV(true, m_size.y());
+ out.lineToH(true, -m_size.x());
+ } else {
+ // Rounded rectangle
+ out.moveTo(false, m_position + vec2(m_roundedCorner.x(), 0.0f));
+ out.lineToH(true, m_size.x()-m_roundedCorner.x()*2.0f);
+ out.curveTo(true, vec2(m_roundedCorner.x()*esvg::kappa90, 0.0f),
+ vec2(m_roundedCorner.x(), m_roundedCorner.y() * (1.0f - esvg::kappa90)),
+ vec2(m_roundedCorner.x(), m_roundedCorner.y()) );
+ out.lineToV(true, m_size.y()-m_roundedCorner.y()*2.0f);
+ out.curveTo(true, vec2(0.0f, m_roundedCorner.y() * esvg::kappa90),
+ vec2(-m_roundedCorner.x()* (1.0f - esvg::kappa90), m_roundedCorner.y()),
+ vec2(-m_roundedCorner.x(), m_roundedCorner.y()) );
+ out.lineToH(true, -(m_size.x()-m_roundedCorner.x()*2.0f));
+ out.curveTo(true, vec2(-m_roundedCorner.x()*esvg::kappa90, 0.0f),
+ vec2(-m_roundedCorner.x(), -m_roundedCorner.y() * (1.0f - esvg::kappa90)),
+ vec2(-m_roundedCorner.x(), -m_roundedCorner.y()) );
+ out.lineToV(true, -(m_size.y()-m_roundedCorner.y()*2.0f));
+ out.curveTo(true, vec2(0.0f, -m_roundedCorner.y() * esvg::kappa90),
+ vec2(m_roundedCorner.x()* (1.0f - esvg::kappa90), -m_roundedCorner.y()),
+ vec2(m_roundedCorner.x(), -m_roundedCorner.y()) );
+ }
+ out.close();
+ return out;
+}
+
+void esvg::Rectangle::draw(esvg::Renderer& _myRenderer, mat2x3& _basicTrans, int32_t _level) {
+ Log.verbose(spacingDist(_level) << "DRAW esvg::Rectangle: fill=" << m_paint.fill.first << "/" << m_paint.fill.second
+ << " stroke=" << m_paint.stroke.first << "/" << m_paint.stroke.second);
+ esvg::render::Path listElement = createPath();
+
+ mat2x3 mtx = m_transformMatrix;
+ mtx *= _basicTrans;
+
+ esvg::render::PointList listPoints;
+ listPoints = listElement.generateListPoints(_level,
+ _myRenderer.getInterpolationRecurtionMax(),
+ _myRenderer.getInterpolationThreshold());
+ //listPoints.applyMatrix(mtx);
+ esvg::render::SegmentList listSegmentFill;
+ esvg::render::SegmentList listSegmentStroke;
+ esvg::render::Weight tmpFill;
+ esvg::render::Weight tmpStroke;
+ ememory::SharedPtr colorFill = esvg::render::createColor(m_paint.fill, mtx);
+ ememory::SharedPtr colorStroke;
+ if (m_paint.strokeWidth > 0.0f) {
+ colorStroke = esvg::render::createColor(m_paint.stroke, mtx);
+ }
+ // Check if we need to display background
+ if (colorFill != null) {
+ listSegmentFill.createSegmentList(listPoints);
+ colorFill->setViewPort(listSegmentFill.getViewPort());
+ listSegmentFill.applyMatrix(mtx);
+ // now, traverse the scanlines and find the intersections on each scanline, use non-zero rule
+ tmpFill.generate(_myRenderer.getSize(),
+ _myRenderer.getNumberSubScanLine(),
+ listSegmentFill);
+ }
+ // check if we need to display stroke:
+ if (colorStroke != null) {
+ listSegmentStroke.createSegmentListStroke(listPoints,
+ m_paint.strokeWidth,
+ m_paint.lineCap,
+ m_paint.lineJoin,
+ m_paint.miterLimit);
+ colorStroke->setViewPort(listSegmentStroke.getViewPort());
+ listSegmentStroke.applyMatrix(mtx);
+ // now, traverse the scanlines and find the intersections on each scanline, use non-zero rule
+ tmpStroke.generate(_myRenderer.getSize(),
+ _myRenderer.getNumberSubScanLine(),
+ listSegmentStroke);
+ }
+ // add on images:
+ _myRenderer.print(tmpFill,
+ colorFill,
+ tmpStroke,
+ colorStroke,
+ m_paint.opacity);
+ #ifdef DEBUG
+ _myRenderer.addDebugSegment(listSegmentFill);
+ _myRenderer.addDebugSegment(listSegmentStroke);
+ #endif
+}
+
+
+void esvg::Rectangle::drawShapePoints(etk::Vector>& _out,
+ int32_t _recurtionMax,
+ float _threshold,
+ mat2x3& _basicTrans,
+ int32_t _level) {
+ Log.verbose(spacingDist(_level) << "DRAW Shape esvg::Rectangle");
+ esvg::render::Path listElement = createPath();
+ mat2x3 mtx = m_transformMatrix;
+ mtx *= _basicTrans;
+ esvg::render::PointList listPoints;
+ listPoints = listElement.generateListPoints(_level, _recurtionMax, _threshold);
+ listPoints.applyMatrix(mtx);
+ for (auto &it : listPoints.m_data) {
+ etk::Vector listPoint;
+ for (auto &itDot : it) {
+ listPoint.pushBack(itDot.m_pos);
+ }
+ _out.pushBack(listPoint);
+ }
+}
diff --git a/src/org/atriasoft/esvg/Rectangle.java b/src/org/atriasoft/esvg/Rectangle.java
new file mode 100644
index 0000000..1234bb4
--- /dev/null
+++ b/src/org/atriasoft/esvg/Rectangle.java
@@ -0,0 +1,31 @@
+/** @file
+ * @author Edouard DUPIN
+ * @copyright 2011, Edouard DUPIN, all right reserved
+ * @license MPL v2.0 (see license file)
+ */
+#pragma once
+
+#include
+
+namespace esvg {
+ class Rectangle : public esvg::Base {
+ private:
+ vec2 m_position; //!< position of the rectangle
+ vec2 m_size; //!< size of the rectangle
+ vec2 m_roundedCorner; //!< property of the rounded corner
+ public:
+ Rectangle(PaintState _parentPaintState);
+ ~Rectangle();
+ bool parseXML(const exml::Element& _element, mat2x3& _parentTrans, vec2& _sizeMax) override;
+ void display(int32_t _spacing) override;
+ void draw(esvg::Renderer& _myRenderer, mat2x3& _basicTrans, int32_t _level) override;
+ void drawShapePoints(etk::Vector>& _out,
+ int32_t _recurtionMax,
+ float _threshold,
+ mat2x3& _basicTrans,
+ int32_t _level=1) override;
+ private:
+ esvg::render::Path createPath();
+ };
+}
+
diff --git a/src/org/atriasoft/esvg/Renderer.cpp b/src/org/atriasoft/esvg/Renderer.cpp
new file mode 100644
index 0000000..4f1acde
--- /dev/null
+++ b/src/org/atriasoft/esvg/Renderer.cpp
@@ -0,0 +1,427 @@
+/** @file
+ * @author Edouard DUPIN
+ * @copyright 2011, Edouard DUPIN, all right reserved
+ * @license MPL v2.0 (see license file)
+ */
+
+#include
+#include
+#include
+#include
+
+esvg::Renderer::Renderer(const ivec2& _size, esvg::Document* _document, bool _visualDebug) :
+#ifdef DEBUG
+ m_visualDebug(_visualDebug),
+ m_factor(1),
+#endif
+ m_interpolationRecurtionMax(10),
+ m_interpolationThreshold(0.25f),
+ m_nbSubScanLine(8),
+ m_document(_document) {
+ #ifdef DEBUG
+ if (m_visualDebug == true) {
+ m_factor = 20;
+ }
+ #endif
+ setSize(_size);
+}
+
+esvg::Renderer::~Renderer() {
+ m_buffer.clear();
+ m_size = ivec2(0,0);
+}
+
+etk::Color esvg::Renderer::mergeColor(etk::Color _base, etk::Color _integration) {
+ etk::Color result;
+ /*
+ if (_integration.a() < _base.a()) {
+ result = _integration;
+ _integration = _base;
+ _base = result;
+ }
+ */
+ result.setR(_integration.a() * _integration.r() + _base.a() * (1.0f - _integration.a()) * _base.r());
+ result.setG(_integration.a() * _integration.g() + _base.a() * (1.0f - _integration.a()) * _base.g());
+ result.setB(_integration.a() * _integration.b() + _base.a() * (1.0f - _integration.a()) * _base.b());
+ result.setA(_integration.a() + _base.a() * (1.0f - _integration.a()));
+ if (result.a() != 0.0f) {
+ float reverse = 1.0f/result.a();
+ result.setR(result.r()*reverse);
+ result.setG(result.g()*reverse);
+ result.setB(result.b()*reverse);
+ }
+ return result;
+}
+
+void esvg::Renderer::print(const esvg::render::Weight& _weightFill,
+ ememory::SharedPtr& _colorFill,
+ const esvg::render::Weight& _weightStroke,
+ ememory::SharedPtr& _colorStroke,
+ float _opacity) {
+ if (_colorFill != null) {
+ //_colorFill->setViewPort(etk::Pair(vec2(0,0), vec2(sizeX, sizeY)));
+ _colorFill->generate(m_document);
+ }
+ if (_colorStroke != null) {
+ //_colorStroke->setViewPort(etk::Pair(vec2(0,0), vec2(sizeX, sizeY)));
+ _colorStroke->generate(m_document);
+ }
+ // all together
+ for (int32_t yyy=0; yyy intermediateColorFill(etk::color::none);
+ etk::Color intermediateColorStroke(etk::color::none);
+ if ( _colorFill != null
+ && valueFill != 0.0f) {
+ intermediateColorFill = _colorFill->getColor(pos);
+ intermediateColorFill.setA(intermediateColorFill.a()*valueFill);
+ }
+ if ( _colorStroke != null
+ && valueStroke != 0.0f) {
+ intermediateColorStroke = _colorStroke->getColor(pos);
+ intermediateColorStroke.setA(intermediateColorStroke.a()*valueStroke);
+ }
+ etk::Color intermediateColor = mergeColor(intermediateColorFill, intermediateColorStroke);
+ intermediateColor.setA(intermediateColor.a() * _opacity);
+ #if DEBUG
+ for (int32_t deltaY=0; deltaY tmpColor = ememory::dynamicPointerCast(_colorFill);
+ if (tmpColor != null) {
+ esvg::render::SegmentList listSegment;
+ // Display bounding box
+ listSegment.addSegment(esvg::render::Point(tmpColor->m_viewPort.first),
+ esvg::render::Point(vec2(tmpColor->m_viewPort.first.x(), tmpColor->m_viewPort.second.y()) ),
+ false);
+ listSegment.addSegment(esvg::render::Point(vec2(tmpColor->m_viewPort.first.x(), tmpColor->m_viewPort.second.y()) ),
+ esvg::render::Point(tmpColor->m_viewPort.second),
+ false);
+ listSegment.addSegment(esvg::render::Point(tmpColor->m_viewPort.second),
+ esvg::render::Point(vec2(tmpColor->m_viewPort.second.x(), tmpColor->m_viewPort.first.y()) ),
+ false);
+ listSegment.addSegment(esvg::render::Point(vec2(tmpColor->m_viewPort.second.x(), tmpColor->m_viewPort.first.y()) ),
+ esvg::render::Point(tmpColor->m_viewPort.first),
+ false);
+ listSegment.applyMatrix(tmpColor->m_matrix);
+ // display the gradient axis
+ listSegment.addSegment(esvg::render::Point(tmpColor->m_pos1),
+ esvg::render::Point(tmpColor->m_pos2),
+ false);
+ /*
+ mat2x3 m_matrix;
+ etk::Pair m_viewPort;
+ vec2 m_pos1;
+ vec2 m_pos2;
+ */
+ addDebugSegment(listSegment);
+ }
+ #endif
+}
+
+#ifdef DEBUG
+ void esvg::Renderer::addDebugSegment(const esvg::render::SegmentList& _listSegment) {
+ if (m_visualDebug == false) {
+ return;
+ }
+ ivec2 dynamicSize = m_size * m_factor;
+ // for each lines:
+ for (int32_t yyy=0; yyy availlableSegmentPixel;
+ for (auto &it : _listSegment.m_data) {
+ if ( it.p0.y() * m_factor <= float(yyy+1)
+ && it.p1.y() * m_factor >= float(yyy)) {
+ availlableSegmentPixel.pushBack(it);
+ }
+ }
+ //find all the segment that cross the middle of the line of the center of the pixel line:
+ float subSamplingCenterPos = yyy + 0.5f;
+ etk::Vector availlableSegment;
+ // find in the subList ...
+ for (auto &it : availlableSegmentPixel) {
+ if ( it.p0.y() * m_factor <= subSamplingCenterPos
+ && it.p1.y() * m_factor >= subSamplingCenterPos ) {
+ availlableSegment.pushBack(it);
+ }
+ }
+ // x position, angle
+ etk::Vector> listPosition;
+ for (auto &it : availlableSegment) {
+ vec2 delta = it.p0 * m_factor - it.p1 * m_factor;
+ // x = coefficent*y+bbb;
+ float coefficient = delta.x()/delta.y();
+ float bbb = it.p0.x() * m_factor - coefficient*it.p0.y() * m_factor;
+ float xpos = coefficient * subSamplingCenterPos + bbb;
+ if ( xpos >= 0
+ && xpos < dynamicSize.x()
+ && yyy >= 0
+ && yyy < dynamicSize.y() ) {
+ if (it.direction == 1.0f) {
+ m_buffer[(dynamicSize.x()*yyy + int32_t(xpos))] = etk::color::blue;
+ } else {
+ m_buffer[(dynamicSize.x()*yyy + int32_t(xpos))] = etk::color::darkRed;
+ }
+ }
+ }
+ }
+ // for each colomn:
+ for (int32_t xxx=0; xxx availlableSegmentPixel;
+ for (auto &it : _listSegment.m_data) {
+ if ( ( it.p0.x() * m_factor <= float(xxx+1)
+ && it.p1.x() * m_factor >= float(xxx) )
+ || ( it.p0.x() * m_factor >= float(xxx+1)
+ && it.p1.x() * m_factor <= float(xxx) ) ) {
+ availlableSegmentPixel.pushBack(it);
+ }
+ }
+ //find all the segment that cross the middle of the line of the center of the pixel line:
+ float subSamplingCenterPos = xxx + 0.5f;
+ etk::Vector availlableSegment;
+ // find in the subList ...
+ for (auto &it : availlableSegmentPixel) {
+ if ( ( it.p0.x() * m_factor <= subSamplingCenterPos
+ && it.p1.x() * m_factor >= subSamplingCenterPos)
+ || ( it.p0.x() * m_factor >= subSamplingCenterPos
+ && it.p1.x() * m_factor <= subSamplingCenterPos) ) {
+ availlableSegment.pushBack(it);
+ }
+ }
+ // x position, angle
+ etk::Vector> listPosition;
+ for (auto &it : availlableSegment) {
+ vec2 delta = it.p0 * m_factor - it.p1 * m_factor;
+ // x = coefficent*y+bbb;
+ if (delta.x() == 0) {
+ continue;
+ }
+ float coefficient = delta.y()/delta.x();
+ float bbb = it.p0.y() * m_factor - coefficient*it.p0.x() * m_factor;
+ float ypos = coefficient * subSamplingCenterPos + bbb;
+ if ( ypos >= 0
+ && ypos < dynamicSize.y()
+ && xxx >= 0
+ && xxx < dynamicSize.y() ) {
+ if (it.direction == 1.0f) {
+ m_buffer[(dynamicSize.x()*int32_t(ypos) + xxx)] = etk::color::blue;
+ } else {
+ m_buffer[(dynamicSize.x()*int32_t(ypos) + xxx)] = etk::color::darkRed;
+ }
+ }
+ }
+ }
+ }
+#endif
+
+
+void esvg::Renderer::writePPM(const etk::Uri& _uri) {
+ if (m_buffer.size() == 0) {
+ return;
+ }
+ auto fileIo = etk::uri::get(_uri);
+ if (fileIo == null) {
+ Log.error("Can not create the uri: " << _uri);
+ return;
+ }
+ if (fileIo->open(etk::io::OpenMode::Write) == false) {
+ Log.error("Can not open (r) the file : " << _uri);
+ return;
+ }
+ int32_t sizeX = m_size.x();
+ int32_t sizeY = m_size.y();
+ #if DEBUG
+ sizeX *= m_factor;
+ sizeY *= m_factor;
+ #endif
+ Log.debug("Generate ppm : " << m_size << " debug size=" << ivec2(sizeX,sizeY));
+ char tmpValue[1024];
+ sprintf(tmpValue, "P6 %d %d 255 ", sizeX, sizeY);
+ fileIo->write(tmpValue,1,sizeof(tmpValue));
+ for (int32_t iii=0 ; iii tmp = m_buffer[iii];
+ fileIo->write(&tmp, 1, 3);
+ }
+ fileIo->close();
+}
+#define PLOPPP
+extern "C" {
+ #pragma pack(push,1)
+ struct bitmapFileHeader {
+ int16_t bfType;
+ int32_t bfSize;
+ int32_t bfReserved;
+ int32_t bfOffBits;
+ };
+ struct bitmapInfoHeader {
+ int32_t biSize;
+ int32_t biWidth;
+ int32_t biHeight;
+ int16_t biPlanes;
+ int16_t biBitCount;
+ int32_t biCompression;
+ int32_t biSizeImage;
+ int32_t biXPelsPerMeter;
+ int32_t biYPelsPerMeter;
+ #ifndef PLOPPP
+ int32_t biClrUsed;
+ int32_t biClrImportant;
+ #else
+ // https://en.wikipedia.org/wiki/BMP_file_format / example 2
+ int32_t biPaletteNumber;
+ int32_t biImportantColor;
+ int32_t biBitMaskRed;
+ int32_t biBitMaskGreen;
+ int32_t biBitMaskBlue;
+ int32_t biBitMaskAlpha;
+ int32_t biLCSColorSpace;
+ int32_t biUnused[16];
+ #endif
+ };
+ #pragma pack(pop)
+}
+void esvg::Renderer::writeBMP(const etk::Uri& _uri) {
+ if (m_buffer.size() == 0) {
+ return;
+ }
+ auto fileIo = etk::uri::get(_uri);
+ if (fileIo == null) {
+ Log.error("Can not create the uri: " << _uri);
+ return;
+ }
+ if (fileIo->open(etk::io::OpenMode::Write) == false) {
+ Log.error("Can not open (r) the file : " << _uri);
+ return;
+ }
+ struct bitmapFileHeader fileHeader;
+ struct bitmapInfoHeader infoHeader;
+
+ int32_t sizeX = m_size.x();
+ int32_t sizeY = m_size.y();
+ #if DEBUG
+ sizeX *= m_factor;
+ sizeY *= m_factor;
+ #endif
+
+ fileHeader.bfType = 0x4D42;
+ fileHeader.bfSize = sizeof(struct bitmapFileHeader) + sizeof(struct bitmapInfoHeader) + sizeX*sizeY*4;
+ fileHeader.bfReserved = 0;
+ fileHeader.bfOffBits = sizeof(struct bitmapFileHeader) + sizeof(struct bitmapInfoHeader);
+
+
+ infoHeader.biSize = sizeof(struct bitmapInfoHeader);
+ infoHeader.biWidth = sizeX;
+ infoHeader.biHeight = sizeY;
+ infoHeader.biPlanes = 1;
+ infoHeader.biBitCount = 32;
+ #ifndef PLOPPP
+ infoHeader.biCompression = 0;
+ #else
+ infoHeader.biCompression = 3;
+ #endif
+ infoHeader.biSizeImage = sizeX*sizeY*4;
+ infoHeader.biXPelsPerMeter = 75;
+ infoHeader.biYPelsPerMeter = 75;
+ #ifndef PLOPPP
+ infoHeader.biClrUsed = 0;
+ infoHeader.biClrImportant = 0;
+ #else
+ infoHeader.biPaletteNumber = 0;
+ infoHeader.biImportantColor = 0;
+ infoHeader.biBitMaskRed = 0xFF000000;
+ infoHeader.biBitMaskGreen = 0x00FF0000;
+ infoHeader.biBitMaskBlue =0x0000FF00;
+ infoHeader.biBitMaskAlpha = 0x000000FF;
+ infoHeader.biLCSColorSpace = 0x73524742; // "Win "
+ for (int32_t jjj=0; jjj<16; ++jjj) {
+ infoHeader.biUnused[jjj] = 0;
+ }
+ infoHeader.biUnused[12] = 0x00000002;
+ #endif
+ // get the data :
+ fileIo->write(&fileHeader, sizeof(struct bitmapFileHeader), 1);
+ fileIo->write(&infoHeader, sizeof(struct bitmapInfoHeader), 1);
+
+ uint8_t data[16];
+ for(int32_t yyy=sizeY-1; yyy>=0; --yyy) {
+ for(int32_t xxx=0; xxx& tmpColor = m_buffer[sizeX*yyy + xxx];
+ uint8_t* pointer = data;
+ #ifndef PLOPPP
+ *pointer++ = tmpColor.a();
+ *pointer++ = tmpColor.r();
+ *pointer++ = tmpColor.g();
+ *pointer++ = tmpColor.b();
+ #else
+ *pointer++ = tmpColor.a();
+ *pointer++ = tmpColor.b();
+ *pointer++ = tmpColor.g();
+ *pointer++ = tmpColor.r();
+ #endif
+ fileIo->write(data,1,4);
+ }
+ }
+ fileIo->close();
+}
+
+
+void esvg::Renderer::setSize(const ivec2& _size) {
+ m_size = _size;
+ m_buffer.resize(m_size.x() * m_size.y()
+ #if DEBUG
+ * m_factor * m_factor
+ #endif
+ , etk::color::none);
+}
+
+const ivec2& esvg::Renderer::getSize() const {
+ return m_size;
+}
+
+etk::Vector> esvg::Renderer::getData() {
+ return m_buffer;
+}
+
+
+
+
+void esvg::Renderer::setInterpolationRecurtionMax(int32_t _value) {
+ m_interpolationRecurtionMax = etk::avg(1, _value, 200);
+}
+
+int32_t esvg::Renderer::getInterpolationRecurtionMax() const {
+ return m_interpolationRecurtionMax;
+}
+
+void esvg::Renderer::setInterpolationThreshold(float _value) {
+ m_interpolationThreshold = etk::avg(0.0f, _value, 20000.0f);
+}
+
+float esvg::Renderer::getInterpolationThreshold() const {
+ return m_interpolationThreshold;
+}
+
+void esvg::Renderer::setNumberSubScanLine(int32_t _value) {
+ m_nbSubScanLine = etk::avg(1, _value, 200);
+}
+
+int32_t esvg::Renderer::getNumberSubScanLine() const {
+ return m_nbSubScanLine;
+}
+
+
diff --git a/src/org/atriasoft/esvg/Renderer.java b/src/org/atriasoft/esvg/Renderer.java
new file mode 100644
index 0000000..420627a
--- /dev/null
+++ b/src/org/atriasoft/esvg/Renderer.java
@@ -0,0 +1,73 @@
+/** @file
+ * @author Edouard DUPIN
+ * @copyright 2011, Edouard DUPIN, all right reserved
+ * @license MPL v2.0 (see license file)
+ */
+#pragma once
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+namespace esvg {
+ class Document;
+ class Renderer {
+ #ifdef DEBUG
+ private:
+ bool m_visualDebug;
+ int32_t m_factor;
+ #endif
+ public:
+ Renderer(const ivec2& _size, esvg::Document* _document, bool _visualDebug=false);
+ ~Renderer();
+ protected:
+ ivec2 m_size;
+ public:
+ void setSize(const ivec2& _size);
+ const ivec2& getSize() const;
+ protected:
+ etk::Vector> m_buffer;
+ public:
+ etk::Vector> getData();
+ protected:
+ int32_t m_interpolationRecurtionMax;
+ public:
+ void setInterpolationRecurtionMax(int32_t _value);
+ int32_t getInterpolationRecurtionMax() const;
+ protected:
+ float m_interpolationThreshold;
+ public:
+ void setInterpolationThreshold(float _value);
+ float getInterpolationThreshold() const;
+ protected:
+ int32_t m_nbSubScanLine;
+ public:
+ void setNumberSubScanLine(int32_t _value);
+ int32_t getNumberSubScanLine() const;
+ public:
+ void writePPM(const etk::Uri& _uri);
+ void writeBMP(const etk::Uri& _uri);
+ protected:
+ etk::Color mergeColor(etk::Color _base, etk::Color _integration);
+ public:
+ void print(const esvg::render::Weight& _weightFill,
+ ememory::SharedPtr& _colorFill,
+ const esvg::render::Weight& _weightStroke,
+ ememory::SharedPtr& _colorStroke,
+ float _opacity);
+ #ifdef DEBUG
+ void addDebugSegment(const esvg::render::SegmentList& _listSegment);
+ void addDebug(const etk::Vector>& _info);
+ #endif
+ protected:
+ esvg::Document* m_document;
+ public:
+ esvg::Document* getMainDocument() {
+ return m_document;
+ }
+ };
+}
+
diff --git a/src/org/atriasoft/esvg/Text.cpp b/src/org/atriasoft/esvg/Text.cpp
new file mode 100644
index 0000000..99ea620
--- /dev/null
+++ b/src/org/atriasoft/esvg/Text.cpp
@@ -0,0 +1,28 @@
+/** @file
+ * @author Edouard DUPIN
+ * @copyright 2011, Edouard DUPIN, all right reserved
+ * @license MPL v2.0 (see license file)
+ */
+
+#include
+#include
+
+esvg::Text::Text(PaintState _parentPaintState) : esvg::Base(_parentPaintState) {
+
+}
+
+esvg::Text::~Text() {
+
+}
+
+bool esvg::Text::parse(const exml::Element& _element, mat2x3& _parentTrans, vec2& _sizeMax) {
+ _sizeMax.setValue(0,0);
+ Log.error("NOT IMPLEMENTED");
+ return false;
+}
+
+void esvg::Text::display(int32_t _spacing) {
+ Log.debug(spacingDist(_spacing) << "Text");
+}
+
+
diff --git a/src/org/atriasoft/esvg/Text.java b/src/org/atriasoft/esvg/Text.java
new file mode 100644
index 0000000..ba00400
--- /dev/null
+++ b/src/org/atriasoft/esvg/Text.java
@@ -0,0 +1,19 @@
+/** @file
+ * @author Edouard DUPIN
+ * @copyright 2011, Edouard DUPIN, all right reserved
+ * @license MPL v2.0 (see license file)
+ */
+#pragma once
+
+#include
+
+namespace esvg {
+ class Text : public esvg::Base {
+ public:
+ Text(PaintState _parentPaintState);
+ ~Text();
+ bool parse(const exml::Element& _element, mat2x3& _parentTrans, vec2& _sizeMax);
+ void display(int32_t _spacing) override;
+ };
+}
+
diff --git a/src/org/atriasoft/esvg/cap.cpp b/src/org/atriasoft/esvg/cap.cpp
new file mode 100644
index 0000000..c77719a
--- /dev/null
+++ b/src/org/atriasoft/esvg/cap.cpp
@@ -0,0 +1,20 @@
+/** @file
+ * @author Edouard DUPIN
+ * @copyright 2011, Edouard DUPIN, all right reserved
+ * @license MPL v2.0 (see license file)
+ */
+
+#include
+#include
+
+static const char* values[] = {
+ "butt",
+ "round",
+ "square"
+};
+
+etk::Stream& esvg::operator <<(etk::Stream& _os, enum esvg::cap _obj) {
+ _os << values[_obj];
+ return _os;
+}
+
diff --git a/src/org/atriasoft/esvg/cap.java b/src/org/atriasoft/esvg/cap.java
new file mode 100644
index 0000000..a7eed9a
--- /dev/null
+++ b/src/org/atriasoft/esvg/cap.java
@@ -0,0 +1,22 @@
+/** @file
+ * @author Edouard DUPIN
+ * @copyright 2011, Edouard DUPIN, all right reserved
+ * @license MPL v2.0 (see license file)
+ */
+#pragma once
+
+#include
+#include
+
+namespace esvg {
+ enum cap {
+ cap_butt,
+ cap_round,
+ cap_square
+ };
+ /**
+ * @brief Debug operator To display the curent element in a Human redeable information
+ */
+ etk::Stream& operator <<(etk::Stream& _os, enum esvg::cap _obj);
+}
+
diff --git a/src/org/atriasoft/esvg/debug.cpp b/src/org/atriasoft/esvg/debug.cpp
new file mode 100644
index 0000000..dcb1404
--- /dev/null
+++ b/src/org/atriasoft/esvg/debug.cpp
@@ -0,0 +1,13 @@
+/** @file
+ * @author Edouard DUPIN
+ * @copyright 2011, Edouard DUPIN, all right reserved
+ * @license MPL v2.0 (see license file)
+ */
+
+#include
+
+int32_t esvg::getLogId() {
+ static int32_t g_val = elog::registerInstance("esvg");
+ return g_val;
+}
+
diff --git a/src/org/atriasoft/esvg/esvg.cpp b/src/org/atriasoft/esvg/esvg.cpp
new file mode 100644
index 0000000..03bad9c
--- /dev/null
+++ b/src/org/atriasoft/esvg/esvg.cpp
@@ -0,0 +1,400 @@
+/** @file
+ * @author Edouard DUPIN
+ * @copyright 2011, Edouard DUPIN, all right reserved
+ * @license MPL v2.0 (see license file)
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+esvg::Document::Document() {
+ m_uri = "";
+ m_version = "0.0";
+ m_loadOK = false;
+ m_size.setValue(0,0);
+}
+
+esvg::Document::~Document() {
+
+}
+
+
+
+void esvg::Document::displayDebug() {
+ Log.debug("Main SVG: size=" << m_size);
+ Log.debug(" refs:");
+ for (size_t iii=0; iii