diff --git a/CMakeLists.txt b/CMakeLists.txt index 131b5f2..c2872b7 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,10 +1,9 @@ cmake_minimum_required(VERSION 3.3) -project(lunasvg VERSION 1.2.2 LANGUAGES CXX) +project(lunasvg VERSION 1.3.0 LANGUAGES CXX) set(CMAKE_CXX_STANDARD 11) -option(BUILD_SHARED_LIBS "Builds shared libraries" ON) option(LUNASVG_BUILD_EXAMPLES "Builds examples" OFF) option(LUNASVG_ENABLE_CAIRO "Enable Cairo 2D Graphics" OFF) diff --git a/README.md b/README.md index 89a53cb..c08ae4d 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,7 @@ int main() - Document Structures: defs, svg, g, use, symbol. - Coordinate Systems, Transformations and Units. - Markers. -- Texts (TODO) : text, tspan, tref, textPath. +- Texts. - Animations (TODO) : animate, animateColor, animateMotion, animateTransform ## depends diff --git a/include/svgdocument.h b/include/svgdocument.h index a194cb7..bed5c86 100755 --- a/include/svgdocument.h +++ b/include/svgdocument.h @@ -79,9 +79,9 @@ class SVGDocument bool loadFromData(const std::string& content); /** - * @brief loadFontFromFile - * @param filename - * @return + * @brief Loads font from a file. + * @param filename Path of the font file to load. + * @return True on success, otherwise false. */ bool loadFontFromFile(const std::string& filename); diff --git a/source/geometry/path.cpp b/source/geometry/path.cpp index 32f9b97..f202fb3 100755 --- a/source/geometry/path.cpp +++ b/source/geometry/path.cpp @@ -88,9 +88,6 @@ void Path::arcTo(double rx, double ry, double xAxisRotation, bool largeArcFlag, y += cp.y; } - if(x == cp.x && y == cp.y) - return; - if(rx == 0.0 || ry == 0.0) { lineTo(x, y); @@ -103,6 +100,9 @@ void Path::arcTo(double rx, double ry, double xAxisRotation, bool largeArcFlag, double dx2 = (cp.x - x) / 2.0; double dy2 = (cp.y - y) / 2.0; + if(dx2 == 0.0 || dy2 == 0.0) + return; + double x1 = (cos_th * dx2 + sin_th * dy2); double y1 = (-sin_th * dx2 + cos_th * dy2); @@ -150,11 +150,11 @@ void Path::arcTo(double rx, double ry, double xAxisRotation, bool largeArcFlag, double angleExtent = sign * ((p / n < -1.0) ? PI : (p / n > 1.0) ? 0 : std::acos(p / n)); if(!sweepFlag && angleExtent > 0.0) { - angleExtent -= PI * 2.0; + angleExtent -= PI * 2.0; } else if(sweepFlag && angleExtent < 0.0) { - angleExtent += PI * 2.0; + angleExtent += PI * 2.0; } int numSegments = int(std::ceil(std::abs(angleExtent) * 2.0 / PI)); @@ -164,21 +164,21 @@ void Path::arcTo(double rx, double ry, double xAxisRotation, bool largeArcFlag, std::size_t pos = 0; for(int i = 0;i < numSegments;i++) { - double angle = angleStart + i * angleIncrement; - double dx = std::cos(angle); - double dy = std::sin(angle); + double angle = angleStart + i * angleIncrement; + double dx = std::cos(angle); + double dy = std::sin(angle); - coords[pos++] = dx - controlLength * dy; - coords[pos++] = dy + controlLength * dx; + coords[pos++] = dx - controlLength * dy; + coords[pos++] = dy + controlLength * dx; - angle += angleIncrement; - dx = std::cos(angle); - dy = std::sin(angle); + angle += angleIncrement; + dx = std::cos(angle); + dy = std::sin(angle); - coords[pos++] = dx + controlLength * dy; - coords[pos++] = dy - controlLength * dx; - coords[pos++] = dx; - coords[pos++] = dy; + coords[pos++] = dx + controlLength * dy; + coords[pos++] = dy - controlLength * dx; + coords[pos++] = dx; + coords[pos++] = dy; } AffineTransform m; diff --git a/source/svgcontentutils.cpp b/source/svgcontentutils.cpp index 702c8cd..ee44c50 100644 --- a/source/svgcontentutils.cpp +++ b/source/svgcontentutils.cpp @@ -121,7 +121,7 @@ static const std::map domelementmap = { {"svg", DOMElementIdSvg}, {"symbol", DOMElementIdSymbol}, {"text", DOMElementIdText}, - {"use", DOMElementIdUse}, + {"use", DOMElementIdUse} }; static const std::map dompropertymap = { @@ -142,7 +142,6 @@ static const std::map dompropertymap = { {"maskUnits", DOMPropertyIdMaskUnits}, {"offset", DOMPropertyIdOffset}, {"orient", DOMPropertyIdOrient}, - {"path", DOMPropertyIdPath}, {"patternContentUnits", DOMPropertyIdPatternContentUnits}, {"patternTransform", DOMPropertyIdPatternTransform}, {"patternUnits", DOMPropertyIdPatternUnits}, @@ -151,7 +150,6 @@ static const std::map dompropertymap = { {"r", DOMPropertyIdR}, {"refX", DOMPropertyIdRefX}, {"refY", DOMPropertyIdRefY}, - {"rotate", DOMPropertyIdRotate}, {"rx", DOMPropertyIdRx}, {"ry", DOMPropertyIdRy}, {"spreadMethod", DOMPropertyIdSpreadMethod}, @@ -165,7 +163,7 @@ static const std::map dompropertymap = { {"xlink:href", DOMPropertyIdHref}, {"y", DOMPropertyIdY}, {"y1", DOMPropertyIdY1}, - {"y2", DOMPropertyIdY2}, + {"y2", DOMPropertyIdY2} }; static const std::map csspropertymap = { @@ -195,7 +193,7 @@ static const std::map csspropertymap = { {"stroke-opacity", CSSPropertyIdStroke_Opacity}, {"stroke-width", CSSPropertyIdStroke_Width}, {"text-anchor", CSSPropertyIdText_Anchor}, - {"visibility", CSSPropertyIdVisibility}, + {"visibility", CSSPropertyIdVisibility} }; bool isElementPermitted(DOMElementID parentId, DOMElementID childId) diff --git a/source/svgcontentutils.h b/source/svgcontentutils.h index 8f47c87..50636d4 100644 --- a/source/svgcontentutils.h +++ b/source/svgcontentutils.h @@ -53,7 +53,6 @@ enum DOMPropertyID DOMPropertyIdMaskUnits, DOMPropertyIdOffset, DOMPropertyIdOrient, - DOMPropertyIdPath, DOMPropertyIdPatternContentUnits, DOMPropertyIdPatternTransform, DOMPropertyIdPatternUnits, @@ -62,7 +61,6 @@ enum DOMPropertyID DOMPropertyIdR, DOMPropertyIdRefX, DOMPropertyIdRefY, - DOMPropertyIdRotate, DOMPropertyIdRx, DOMPropertyIdRy, DOMPropertyIdSpreadMethod, diff --git a/source/svggeometryelement.cpp b/source/svggeometryelement.cpp index ad1003c..286a55d 100755 --- a/source/svggeometryelement.cpp +++ b/source/svggeometryelement.cpp @@ -285,7 +285,7 @@ SVGElementImpl* SVGLineElement::clone(SVGDocument* document) const { SVGLineElement* e = new SVGLineElement(document); baseClone(*e); - return e; + return e; } SVGPathElement::SVGPathElement(SVGDocument* document) diff --git a/source/svglength.cpp b/source/svglength.cpp index ddc8bf9..9be548e 100755 --- a/source/svglength.cpp +++ b/source/svglength.cpp @@ -81,9 +81,7 @@ double SVGLength::value(double dpi) const double SVGLength::value(const RenderState& state, double max) const { if(m_unit == LengthUnitPercent) - { return m_value * max / 100.0; - } return value(state.dpi); } diff --git a/source/svgtextelement.cpp b/source/svgtextelement.cpp index 24e5ef3..740bbfb 100644 --- a/source/svgtextelement.cpp +++ b/source/svgtextelement.cpp @@ -15,41 +15,7 @@ SVGTextElement::SVGTextElement(SVGDocument* document) addToPropertyMap(m_y); } -inline bool parseEntity(const char* ptr, const char* end, std::uint32_t& codepoint) -{ - if(*ptr == '#') - { - ++ptr; - int base = 10; - if(*ptr == 'x') - { - ++ptr; - base = 16; - } - - if(!Utils::parseInteger(ptr, codepoint, base)) - return false; - return ptr == end; - } - - static const std::map entitymap = - { - {"amp", 38}, - {"lt", 60}, - {"gt", 62}, - {"quot", 34}, - {"apos", 39}, - }; - - std::string name(ptr, end); - std::map::const_iterator it = entitymap.find(name); - if(it == entitymap.end()) - return false; - codepoint = it->second; - return true; -} - -inline const char* decode(const char* begin, const char* end, std::uint32_t& output) +inline bool decodeUtf8(const char*& ptr, const char* end, std::uint32_t& output) { static const int trailing[256] = { @@ -68,28 +34,23 @@ inline const char* decode(const char* begin, const char* end, std::uint32_t& out 0x00000000, 0x00003080, 0x000E2080, 0x03C82080, 0xFA082080, 0x82082080 }; - int trailingBytes = trailing[static_cast(*begin)]; - if(begin + trailingBytes < end) - { - output = 0; - switch(trailingBytes) - { - case 5: output += static_cast(*begin++); output <<= 6; - case 4: output += static_cast(*begin++); output <<= 6; - case 3: output += static_cast(*begin++); output <<= 6; - case 2: output += static_cast(*begin++); output <<= 6; - case 1: output += static_cast(*begin++); output <<= 6; - case 0: output += static_cast(*begin++); - } + int trailingBytes = trailing[static_cast(*ptr)]; + if(ptr + trailingBytes >= end) + return false; - output -= offsets[trailingBytes]; - } - else + output = 0; + switch(trailingBytes) { - begin = end; + case 5: output += static_cast(*ptr++); output <<= 6; + case 4: output += static_cast(*ptr++); output <<= 6; + case 3: output += static_cast(*ptr++); output <<= 6; + case 2: output += static_cast(*ptr++); output <<= 6; + case 1: output += static_cast(*ptr++); output <<= 6; + case 0: output += static_cast(*ptr++); } - return begin; + output -= offsets[trailingBytes]; + return true; } std::vector lunasvg::SVGTextElement::buildTextContent() const @@ -111,22 +72,53 @@ std::vector lunasvg::SVGTextElement::buildTextContent() const if(*ptr == '&') { ++ptr; - const char* start = ptr; - while(ptr < end && *ptr!=';') + if(*ptr == '#') + { ++ptr; - if(ptr >= end || *ptr!=';') - break; - std::uint32_t codepoint = 0; - if(!parseEntity(start, ptr, codepoint)) - break; - out.push_back(codepoint); - ++ptr; - continue; + int base = 10; + if(*ptr == 'x') + { + ++ptr; + base = 16; + } + + std::uint32_t codepoint; + if(!Utils::parseInteger(ptr, codepoint, base)) + break; + if(ptr >= end || *ptr != ';') + break; + ++ptr; + out.push_back(codepoint); + } + else + { + static const std::map entitymap = + { + {"amp", 38}, + {"lt", 60}, + {"gt", 62}, + {"quot", 34}, + {"apos", 39} + }; + + const char* start = ptr; + while(ptr < end && *ptr!=';') + ++ptr; + if(ptr >= end || *ptr!=';') + break; + std::string name(start, ptr); + std::map::const_iterator it = entitymap.find(name); + if(it == entitymap.end()) + break; + ++ptr; + out.push_back(it->second); + } } else { - std::uint32_t codepoint = 0; - ptr = decode(ptr, end, codepoint); + std::uint32_t codepoint; + if(!decodeUtf8(ptr, end, codepoint)) + break; out.push_back(codepoint); } }