Browse Source

Added XmlElement methods to help parse namespaces on tagnames. Updated SVG parser to handle files which use namespaces.

tags/2021-05-28
jules 13 years ago
parent
commit
93dd9757e5
3 changed files with 98 additions and 77 deletions
  1. +29
    -24
      modules/juce_core/xml/juce_XmlElement.cpp
  2. +13
    -6
      modules/juce_core/xml/juce_XmlElement.h
  3. +56
    -47
      modules/juce_gui_basics/drawables/juce_SVGParser.cpp

+ 29
- 24
modules/juce_core/xml/juce_XmlElement.cpp View File

@@ -29,9 +29,8 @@ XmlElement::XmlAttributeNode::XmlAttributeNode (const XmlAttributeNode& other) n
{
}
XmlElement::XmlAttributeNode::XmlAttributeNode (const String& name_, const String& value_) noexcept
: name (name_),
value (value_)
XmlElement::XmlAttributeNode::XmlAttributeNode (const String& n, const String& v) noexcept
: name (n), value (v)
{
#if JUCE_DEBUG
// this checks whether the attribute name string contains any illegal characters..
@@ -46,14 +45,14 @@ inline bool XmlElement::XmlAttributeNode::hasName (const String& nameToMatch) co
}
//==============================================================================
XmlElement::XmlElement (const String& tagName_) noexcept
: tagName (tagName_)
XmlElement::XmlElement (const String& tag) noexcept
: tagName (tag)
{
// the tag name mustn't be empty, or it'll look like a text element!
jassert (tagName_.containsNonWhitespaceChars())
jassert (tag.containsNonWhitespaceChars())
// The tag can't contain spaces or other characters that would create invalid XML!
jassert (! tagName_.containsAnyOf (" <>/&"));
jassert (! tag.containsAnyOf (" <>/&"));
}
XmlElement::XmlElement (int /*dummy*/) noexcept
@@ -362,24 +361,30 @@ bool XmlElement::writeToFile (const File& file,
}
//==============================================================================
bool XmlElement::hasTagName (const String& tagNameWanted) const noexcept
bool XmlElement::hasTagName (const String& possibleTagName) const noexcept
{
#if JUCE_DEBUG
// if debugging, check that the case is actually the same, because
// valid xml is case-sensitive, and although this lets it pass, it's
// better not to..
if (tagName.equalsIgnoreCase (tagNameWanted))
{
jassert (tagName == tagNameWanted);
return true;
}
else
{
return false;
}
#else
return tagName.equalsIgnoreCase (tagNameWanted);
#endif
const bool matches = tagName.equalsIgnoreCase (possibleTagName);
// XML tags should be case-sensitive, so although this method allows a
// case-insensitive match to pass, you should try to avoid this.
jassert ((! matches) || tagName == possibleTagName);
return matches;
}
String XmlElement::getNamespace() const
{
return tagName.upToFirstOccurrenceOf (":", false, false);
}
String XmlElement::getTagNameWithoutNamespace() const
{
return tagName.fromLastOccurrenceOf (":", false, false);
}
bool XmlElement::hasTagNameIgnoringNamespace (const String& possibleTagName) const
{
return hasTagName (possibleTagName) || getTagNameWithoutNamespace() == possibleTagName;
}
XmlElement* XmlElement::getNextElementWithTagName (const String& requiredTagName) const


+ 13
- 6
modules/juce_core/xml/juce_XmlElement.h View File

@@ -249,22 +249,29 @@ public:
//==============================================================================
/** Returns this element's tag type name.
E.g. for an element such as \<MOOSE legs="4" antlers="2">, this would return
"MOOSE".
E.g. for an element such as \<MOOSE legs="4" antlers="2">, this would return "MOOSE".
@see hasTagName
*/
inline const String& getTagName() const noexcept { return tagName; }
/** Tests whether this element has a particular tag name.
/** Returns the namespace portion of the tag-name, or an empty string if none is specified. */
String getNamespace() const;
@param possibleTagName the tag name you're comparing it with
/** Returns the part of the tag-name that follows any namespace declaration. */
String getTagNameWithoutNamespace() const;
/** Tests whether this element has a particular tag name.
@param possibleTagName the tag name you're comparing it with
@see getTagName
*/
bool hasTagName (const String& possibleTagName) const noexcept;
/** Tests whether this element has a particular tag name, ignoring any XML namespace prefix.
So a test for e.g. "xyz" will return true for "xyz" and also "foo:xyz", "bar::xyz", etc.
@see getTagName
*/
bool hasTagNameIgnoringNamespace (const String& possibleTagName) const;
//==============================================================================
/** Returns the number of XML attributes this element contains.


+ 56
- 47
modules/juce_gui_basics/drawables/juce_SVGParser.cpp View File

@@ -38,7 +38,7 @@ public:
//==============================================================================
Drawable* parseSVGElement (const XmlElement& xml)
{
if (! xml.hasTagName ("svg"))
if (! xml.hasTagNameIgnoringNamespace ("svg"))
return nullptr;
DrawableComposite* const drawable = new DrawableComposite();
@@ -105,7 +105,7 @@ public:
if (viewBoxH == 0) newState.viewBoxH = newState.height;
}
newState.parseSubElements (xml, drawable);
newState.parseSubElements (xml, *drawable);
drawable->setContentArea (RelativeRectangle (Rectangle<float> (newState.viewBoxW, newState.viewBoxH)));
drawable->resetBoundingBoxToContentArea();
@@ -121,27 +121,30 @@ private:
String cssStyleText;
//==============================================================================
void parseSubElements (const XmlElement& xml, DrawableComposite* const parentDrawable)
void parseSubElements (const XmlElement& xml, DrawableComposite& parentDrawable)
{
forEachXmlChildElement (xml, e)
{
Drawable* d = nullptr;
if (e->hasTagName ("g")) d = parseGroupElement (*e);
else if (e->hasTagName ("svg")) d = parseSVGElement (*e);
else if (e->hasTagName ("path")) d = parsePath (*e);
else if (e->hasTagName ("rect")) d = parseRect (*e);
else if (e->hasTagName ("circle")) d = parseCircle (*e);
else if (e->hasTagName ("ellipse")) d = parseEllipse (*e);
else if (e->hasTagName ("line")) d = parseLine (*e);
else if (e->hasTagName ("polyline")) d = parsePolygon (*e, true);
else if (e->hasTagName ("polygon")) d = parsePolygon (*e, false);
else if (e->hasTagName ("text")) d = parseText (*e);
else if (e->hasTagName ("switch")) d = parseSwitch (*e);
else if (e->hasTagName ("style")) parseCSSStyle (*e);
parentDrawable->addAndMakeVisible (d);
}
parentDrawable.addAndMakeVisible (parseSubElement (*e));
}
Drawable* parseSubElement (const XmlElement& xml)
{
const String tag (xml.getTagNameWithoutNamespace());
if (tag == "g") return parseGroupElement (xml);
if (tag == "svg") return parseSVGElement (xml);
if (tag == "path") return parsePath (xml);
if (tag == "rect") return parseRect (xml);
if (tag == "circle") return parseCircle (xml);
if (tag == "ellipse") return parseEllipse (xml);
if (tag == "line") return parseLine (xml);
if (tag == "polyline") return parsePolygon (xml, true);
if (tag == "polygon") return parsePolygon (xml, false);
if (tag == "text") return parseText (xml);
if (tag == "switch") return parseSwitch (xml);
if (tag == "style") parseCSSStyle (xml);
return nullptr;
}
DrawableComposite* parseSwitch (const XmlElement& xml)
@@ -163,11 +166,11 @@ private:
SVGState newState (*this);
newState.addTransform (xml);
newState.parseSubElements (xml, drawable);
newState.parseSubElements (xml, *drawable);
}
else
{
parseSubElements (xml, drawable);
parseSubElements (xml, *drawable);
}
drawable->resetContentAreaAndBoundingBoxToFitChildren();
@@ -412,26 +415,26 @@ private:
if (hasRX || hasRY)
{
float rx = getCoordLength (xml.getStringAttribute ("rx"), viewBoxW);
float ry = getCoordLength (xml.getStringAttribute ("ry"), viewBoxH);
float rx = getCoordLength (xml, "rx", viewBoxW);
float ry = getCoordLength (xml, "ry", viewBoxH);
if (! hasRX)
rx = ry;
else if (! hasRY)
ry = rx;
rect.addRoundedRectangle (getCoordLength (xml.getStringAttribute ("x"), viewBoxW),
getCoordLength (xml.getStringAttribute ("y"), viewBoxH),
getCoordLength (xml.getStringAttribute ("width"), viewBoxW),
getCoordLength (xml.getStringAttribute ("height"), viewBoxH),
rect.addRoundedRectangle (getCoordLength (xml, "x", viewBoxW),
getCoordLength (xml, "y", viewBoxH),
getCoordLength (xml, "width", viewBoxW),
getCoordLength (xml, "height", viewBoxH),
rx, ry);
}
else
{
rect.addRectangle (getCoordLength (xml.getStringAttribute ("x"), viewBoxW),
getCoordLength (xml.getStringAttribute ("y"), viewBoxH),
getCoordLength (xml.getStringAttribute ("width"), viewBoxW),
getCoordLength (xml.getStringAttribute ("height"), viewBoxH));
rect.addRectangle (getCoordLength (xml, "x", viewBoxW),
getCoordLength (xml, "y", viewBoxH),
getCoordLength (xml, "width", viewBoxW),
getCoordLength (xml, "height", viewBoxH));
}
return parseShape (xml, rect);
@@ -441,9 +444,9 @@ private:
{
Path circle;
const float cx = getCoordLength (xml.getStringAttribute ("cx"), viewBoxW);
const float cy = getCoordLength (xml.getStringAttribute ("cy"), viewBoxH);
const float radius = getCoordLength (xml.getStringAttribute ("r"), viewBoxW);
const float cx = getCoordLength (xml, "cx", viewBoxW);
const float cy = getCoordLength (xml, "cy", viewBoxH);
const float radius = getCoordLength (xml, "r", viewBoxW);
circle.addEllipse (cx - radius, cy - radius, radius * 2.0f, radius * 2.0f);
@@ -454,10 +457,10 @@ private:
{
Path ellipse;
const float cx = getCoordLength (xml.getStringAttribute ("cx"), viewBoxW);
const float cy = getCoordLength (xml.getStringAttribute ("cy"), viewBoxH);
const float radiusX = getCoordLength (xml.getStringAttribute ("rx"), viewBoxW);
const float radiusY = getCoordLength (xml.getStringAttribute ("ry"), viewBoxH);
const float cx = getCoordLength (xml, "cx", viewBoxW);
const float cy = getCoordLength (xml, "cy", viewBoxH);
const float radiusX = getCoordLength (xml, "rx", viewBoxW);
const float radiusY = getCoordLength (xml, "ry", viewBoxH);
ellipse.addEllipse (cx - radiusX, cy - radiusY, radiusX * 2.0f, radiusY * 2.0f);
@@ -468,10 +471,10 @@ private:
{
Path line;
const float x1 = getCoordLength (xml.getStringAttribute ("x1"), viewBoxW);
const float y1 = getCoordLength (xml.getStringAttribute ("y1"), viewBoxH);
const float x2 = getCoordLength (xml.getStringAttribute ("x2"), viewBoxW);
const float y2 = getCoordLength (xml.getStringAttribute ("y2"), viewBoxH);
const float x1 = getCoordLength (xml, "x1", viewBoxW);
const float y1 = getCoordLength (xml, "y1", viewBoxH);
const float x2 = getCoordLength (xml, "x2", viewBoxW);
const float y2 = getCoordLength (xml, "y2", viewBoxH);
line.startNewSubPath (x1, y1);
line.lineTo (x2, y2);
@@ -615,7 +618,7 @@ private:
jassert (gradient.getNumColours() > 0);
gradient.isRadial = fillXml->hasTagName ("radialGradient");
gradient.isRadial = fillXml->hasTagNameIgnoringNamespace ("radialGradient");
float gradientWidth = viewBoxW;
float gradientHeight = viewBoxH;
@@ -722,7 +725,8 @@ private:
.upToLastOccurrenceOf (")", false, false).trim());
if (const XmlElement* const fillXml = findElementForId (topLevelXml, id))
if (fillXml->hasTagName ("linearGradient") || fillXml->hasTagName ("radialGradient"))
if (fillXml->hasTagNameIgnoringNamespace ("linearGradient")
|| fillXml->hasTagNameIgnoringNamespace ("radialGradient"))
return getGradientFillType (fillXml, path, opacity);
}
@@ -788,7 +792,7 @@ private:
Drawable* s = parseShape (*e, path);
delete s; // xxx not finished!
}
else if (e->hasTagName ("tspan"))
else if (e->hasTagNameIgnoringNamespace ("tspan"))
{
Drawable* s = parseText (*e);
delete s; // xxx not finished!
@@ -857,6 +861,11 @@ private:
return n;
}
float getCoordLength (const XmlElement& xml, const char* attName, const float sizeForProportions) const
{
return getCoordLength (xml.getStringAttribute (attName), sizeForProportions);
}
void getCoordList (Array <float>& coords, const String& list,
const bool allowUnits, const bool isX) const
{


Loading…
Cancel
Save