svg_loader: intro to the implementation of the css internal style sheets parsing

Function simpleXmlParseCSSAttribute() used to parse the data inside the style tag.
For now the supported formats are: tag {}, .name {}, tag.name{}

_svgLoaderParserXmlStyle() used to deal with the results of the above - to create
the proper nodes. Will work after create...Node() are changed.

Note:
The geometric attributes are not copied from the node defining the style
to the node using it. The SVG2 standard has to be checked to decide
whether it should be supported.
This commit is contained in:
Mira Grudzinska 2022-01-12 16:23:22 +01:00 committed by Hermet Park
parent 0f51d798ce
commit c3ed02fd22
4 changed files with 176 additions and 62 deletions

View file

@ -80,6 +80,9 @@ typedef SvgNode* (*FactoryMethod)(SvgLoaderData* loader, SvgNode* parent, const
typedef SvgStyleGradient* (*GradientFactoryMethod)(SvgLoaderData* loader, const char* buf, unsigned bufLength);
static void _copyAttr(SvgNode* to, const SvgNode* from, bool copyGeomAttrib = true);
static char* _skipSpace(const char* str, const char* end)
{
while (((end && str < end) || (!end && *str != '\0')) && isspace(*str)) {
@ -947,12 +950,32 @@ static void _handleDisplayAttr(TVG_UNUSED SvgLoaderData* loader, SvgNode* node,
}
static void _handleCssClassAttr(TVG_UNUSED SvgLoaderData* loader, SvgNode* node, const char* value)
static SvgNode* _findCssStyleNode(const SvgNode* cssStyle, const char* title)
{
if (!cssStyle) return nullptr;
auto child = cssStyle->child.data;
for (uint32_t i = 0; i < cssStyle->child.count; ++i, ++child) {
if (((*child)->id) && !strcmp((*child)->id, title)) return (*child);
}
return nullptr;
}
static void _handleCssClassAttr(SvgLoaderData* loader, SvgNode* node, const char* value)
{
auto cssClass = &node->style->cssClass;
if (*cssClass && value) free(*cssClass);
*cssClass = _copyId(value);
//TODO: works only if style was defined before it is used
if (auto cssNode = _findCssStyleNode(loader->cssStyle, *cssClass)) {
//TODO: check SVG2 stndard - should the geometric properties be copied?
_copyAttr(node, cssNode, false);
}
}
@ -1908,7 +1931,7 @@ static void _styleCopy(SvgStyleProperty* to, const SvgStyleProperty* from)
}
static void _copyAttr(SvgNode* to, const SvgNode* from)
static void _copyAttr(SvgNode* to, const SvgNode* from, bool copyGeomAttrib)
{
//Copy matrix attribute
if (from->transform) {
@ -1923,6 +1946,7 @@ static void _copyAttr(SvgNode* to, const SvgNode* from)
if (from->style->clipPath.url) to->style->clipPath.url = strdup(from->style->clipPath.url);
if (from->style->mask.url) to->style->mask.url = strdup(from->style->mask.url);
if (copyGeomAttrib) {
//Copy node attribute
switch (from->type) {
case SvgNodeType::Circle: {
@ -1961,17 +1985,15 @@ static void _copyAttr(SvgNode* to, const SvgNode* from)
break;
}
case SvgNodeType::Polygon: {
if ((to->node.polygon.pointsCount = from->node.polygon.pointsCount)) {
to->node.polygon.pointsCount = from->node.polygon.pointsCount;
to->node.polygon.points = (float*)malloc(to->node.polygon.pointsCount * sizeof(float));
memcpy(to->node.polygon.points, from->node.polygon.points, to->node.polygon.pointsCount * sizeof(float));
}
break;
}
case SvgNodeType::Polyline: {
if ((to->node.polyline.pointsCount = from->node.polyline.pointsCount)) {
to->node.polyline.pointsCount = from->node.polyline.pointsCount;
to->node.polyline.points = (float*)malloc(to->node.polyline.pointsCount * sizeof(float));
memcpy(to->node.polyline.points, from->node.polyline.points, to->node.polyline.pointsCount * sizeof(float));
}
break;
}
case SvgNodeType::Image: {
@ -1987,6 +2009,7 @@ static void _copyAttr(SvgNode* to, const SvgNode* from)
}
}
}
}
static void _cloneNode(SvgNode* from, SvgNode* parent, int depth)
@ -2093,6 +2116,7 @@ static SvgNode* _createUseNode(SvgLoaderData* loader, SvgNode* parent, const cha
return loader->svgParse->node;
}
//TODO: Implement 'text' primitive
static constexpr struct
{
@ -2583,6 +2607,7 @@ static void _svgLoaderParserXmlOpen(SvgLoaderData* loader, const char* content,
GradientFactoryMethod gradientMethod;
SvgNode *node = nullptr, *parent = nullptr;
loader->level++;
loader->style = false;
attrs = simpleXmlFindAttributesTag(content, length);
if (!attrs) {
@ -2613,7 +2638,10 @@ static void _svgLoaderParserXmlOpen(SvgLoaderData* loader, const char* content,
if (loader->stack.count > 0) parent = loader->stack.data[loader->stack.count - 1];
else parent = loader->doc;
node = method(loader, parent, attrs, attrsLength);
if (!strcmp(tagName, "style")) loader->cssStyle = node;
if (!strcmp(tagName, "style")) {
loader->cssStyle = node;
loader->style = true;
}
}
if (!node) return;
@ -2654,6 +2682,46 @@ static void _svgLoaderParserXmlOpen(SvgLoaderData* loader, const char* content,
}
static void _svgLoaderParserXmlStyle(SvgLoaderData* loader, const char* content, unsigned int length)
{
char* tag;
char* name;
const char* attrs = nullptr;
unsigned int attrsLength = 0;
FactoryMethod method;
GradientFactoryMethod gradientMethod;
SvgNode *node = nullptr;
const char *buf = content;
unsigned buflen = length;
while (auto next = simpleXmlParseCSSAttribute(buf, buflen, &tag, &name, &attrs, &attrsLength)) {
if ((method = _findGroupFactory(tag))) {
//TODO - node->id ??? add additional var for svgnode?
if ((node = method(loader, loader->cssStyle, attrs, attrsLength))) node->id = _copyId(name);
} else if ((method = _findGraphicsFactory(tag))) {
if ((node = method(loader, loader->cssStyle, attrs, attrsLength))) node->id = _copyId(name);
//TODO - implement
} else if ((gradientMethod = _findGradientFactory(tag))) {
//TODO - implement
//SvgStyleGradient* gradient = gradientMethod(loader, attrs, attrsLength);
} else if (!strcmp(tag, "stop")) {
//TODO - implement
} else if (!isIgnoreUnsupportedLogElements(tag)) {
TVGLOG("SVG", "Unsupported elements used [Elements: %s]", tag);
}
buflen -= next - buf;
buf = next;
free(tag);
free(name);
}
}
static bool _svgLoaderParser(void* data, SimpleXMLType type, const char* content, unsigned int length)
{
SvgLoaderData* loader = (SvgLoaderData*)data;
@ -2672,7 +2740,10 @@ static bool _svgLoaderParser(void* data, SimpleXMLType type, const char* content
break;
}
case SimpleXMLType::Data:
case SimpleXMLType::CData:
case SimpleXMLType::CData: {
if (loader->style) _svgLoaderParserXmlStyle(loader, content, length);
break;
}
case SimpleXMLType::DoctypeChild: {
break;
}

View file

@ -415,6 +415,7 @@ struct SvgLoaderData
Array<SvgNodeIdPair> cloneNodes;
int level = 0;
bool result = false;
bool style = false; //TODO: find a better sollution?
};
/*

View file

@ -509,6 +509,47 @@ bool simpleXmlParseW3CAttribute(const char* buf, simpleXMLAttributeCb func, cons
}
/*
* Supported formats:
* tag {}, .name {}, tag.name{}
*/
const char* simpleXmlParseCSSAttribute(const char* buf, unsigned bufLength, char** tag, char** name, const char** attrs, unsigned* attrsLength)
{
if (!buf) return nullptr;
*tag = *name = nullptr;
*attrsLength = 0;
auto itr = _simpleXmlSkipWhiteSpace(buf, buf + bufLength);
auto itrEnd = (const char*)memchr(buf, '{', bufLength);
if (!itrEnd || itr == itrEnd) return nullptr;
auto nextElement = (const char*)memchr(itrEnd, '}', bufLength - (itrEnd - buf));
if (!nextElement) return nullptr;
*attrs = itrEnd + 1;
*attrsLength = nextElement - *attrs;
const char *p;
itrEnd = _simpleXmlUnskipWhiteSpace(itrEnd, itr);
if (*(itrEnd - 1) == '.') return nullptr;
for (p = itr; p < itrEnd; p++) {
if (*p == '.') break;
}
if (p == itr) *tag = strdup("all");
else *tag = strndup(itr, p - itr);
if (p == itrEnd) *name = nullptr;
else *name = strndup(p + 1, itrEnd - p - 1);
return (nextElement ? nextElement + 1 : nullptr);
}
const char* simpleXmlFindAttributesTag(const char* buf, unsigned bufLength)
{
const char *itr = buf, *itrEnd = buf + bufLength;

View file

@ -50,6 +50,7 @@ typedef bool (*simpleXMLAttributeCb)(void* data, const char* key, const char* va
bool simpleXmlParseAttributes(const char* buf, unsigned buflen, simpleXMLAttributeCb func, const void* data);
bool simpleXmlParse(const char* buf, unsigned buflen, bool strip, simpleXMLCb func, const void* data);
bool simpleXmlParseW3CAttribute(const char* buf, simpleXMLAttributeCb func, const void* data);
const char* simpleXmlParseCSSAttribute(const char* buf, unsigned bufLength, char** tag, char** name, const char** attrs, unsigned* attrsLength);
const char* simpleXmlFindAttributesTag(const char* buf, unsigned buflen);
bool isIgnoreUnsupportedLogElements(const char* tagName);
const char* simpleXmlNodeTypeToString(SvgNodeType type);