Squashed 'external/lunasvg/' changes from a92aa90fa..0562a5dcc

0562a5dcc Support SVG files with invalid size #117
5732df547 Refactor parsePath

git-subtree-dir: external/lunasvg
git-subtree-split: 0562a5dcc8c25e59c060ee73d6d4d538f172d642
This commit is contained in:
Leon Styhre 2022-11-05 13:56:31 +01:00
parent aad9e2d48d
commit f44be39f5e
2 changed files with 59 additions and 62 deletions

View file

@ -173,6 +173,7 @@ Path Parser::parsePath(const std::string& string)
return Path{}; return Path{};
auto command = *ptr++; auto command = *ptr++;
auto lastCommand = command;
double c[6]; double c[6];
bool f[2]; bool f[2];
@ -184,9 +185,7 @@ Path Parser::parsePath(const std::string& string)
while(true) while(true)
{ {
Utils::skipWs(ptr, end); Utils::skipWs(ptr, end);
switch(command) { if(command == 'M' || command == 'm') {
case 'M':
case 'm':
if(!parseNumberList(ptr, end, c, 2)) if(!parseNumberList(ptr, end, c, 2))
return path; return path;
@ -197,12 +196,10 @@ Path Parser::parsePath(const std::string& string)
} }
path.moveTo(c[0], c[1]); path.moveTo(c[0], c[1]);
startPoint.x = currentPoint.x = controlPoint.x = c[0]; startPoint.x = currentPoint.x = c[0];
startPoint.y = currentPoint.y = controlPoint.y = c[1]; startPoint.y = currentPoint.y = c[1];
command = command == 'm' ? 'l' : 'L'; command = command == 'm' ? 'l' : 'L';
break; } else if(command == 'L' || command == 'l') {
case 'L':
case 'l':
if(!parseNumberList(ptr, end, c, 2)) if(!parseNumberList(ptr, end, c, 2))
return path; return path;
@ -213,11 +210,27 @@ Path Parser::parsePath(const std::string& string)
} }
path.lineTo(c[0], c[1]); path.lineTo(c[0], c[1]);
currentPoint.x = controlPoint.x = c[0]; currentPoint.x = c[0];
currentPoint.y = controlPoint.y = c[1]; currentPoint.y = c[1];
break; } else if(command == 'H' || command == 'h') {
case 'Q': if(!parseNumberList(ptr, end, c, 1))
case 'q': return path;
if(command == 'h')
c[0] += currentPoint.x;
path.lineTo(c[0], currentPoint.y);
currentPoint.x = c[0];
} else if(command == 'V' || command == 'v') {
if(!parseNumberList(ptr, end, c + 1, 1))
return path;
if(command == 'v')
c[1] += currentPoint.y;
path.lineTo(currentPoint.x, c[1]);
currentPoint.y = c[1];
} else if(command == 'Q' || command == 'q') {
if(!parseNumberList(ptr, end, c, 4)) if(!parseNumberList(ptr, end, c, 4))
return path; return path;
@ -234,9 +247,7 @@ Path Parser::parsePath(const std::string& string)
controlPoint.y = c[1]; controlPoint.y = c[1];
currentPoint.x = c[2]; currentPoint.x = c[2];
currentPoint.y = c[3]; currentPoint.y = c[3];
break; } else if(command == 'C' || command == 'c') {
case 'C':
case 'c':
if(!parseNumberList(ptr, end, c, 6)) if(!parseNumberList(ptr, end, c, 6))
return path; return path;
@ -255,11 +266,15 @@ Path Parser::parsePath(const std::string& string)
controlPoint.y = c[3]; controlPoint.y = c[3];
currentPoint.x = c[4]; currentPoint.x = c[4];
currentPoint.y = c[5]; currentPoint.y = c[5];
break; } else if(command == 'T' || command == 't') {
case 'T': if(lastCommand != 'Q' && lastCommand != 'q' && lastCommand != 'T' && lastCommand != 't') {
case 't': c[0] = currentPoint.x;
c[0] = 2 * currentPoint.x - controlPoint.x; c[1] = currentPoint.y;
c[1] = 2 * currentPoint.y - controlPoint.y; } else {
c[0] = 2 * currentPoint.x - controlPoint.x;
c[1] = 2 * currentPoint.y - controlPoint.y;
}
if(!parseNumberList(ptr, end, c + 2, 2)) if(!parseNumberList(ptr, end, c + 2, 2))
return path; return path;
@ -274,11 +289,15 @@ Path Parser::parsePath(const std::string& string)
controlPoint.y = c[1]; controlPoint.y = c[1];
currentPoint.x = c[2]; currentPoint.x = c[2];
currentPoint.y = c[3]; currentPoint.y = c[3];
break; } else if(command == 'S' || command == 's') {
case 'S': if(lastCommand != 'C' && lastCommand != 'c' && lastCommand != 'S' && lastCommand != 's') {
case 's': c[0] = currentPoint.x;
c[0] = 2 * currentPoint.x - controlPoint.x; c[1] = currentPoint.y;
c[1] = 2 * currentPoint.y - controlPoint.y; } else {
c[0] = 2 * currentPoint.x - controlPoint.x;
c[1] = 2 * currentPoint.y - controlPoint.y;
}
if(!parseNumberList(ptr, end, c + 2, 4)) if(!parseNumberList(ptr, end, c + 2, 4))
return path; return path;
@ -295,33 +314,7 @@ Path Parser::parsePath(const std::string& string)
controlPoint.y = c[3]; controlPoint.y = c[3];
currentPoint.x = c[4]; currentPoint.x = c[4];
currentPoint.y = c[5]; currentPoint.y = c[5];
break; } else if(command == 'A' || command == 'a') {
case 'H':
case 'h':
if(!parseNumberList(ptr, end, c, 1))
return path;
if(command == 'h')
c[0] += currentPoint.x;
path.lineTo(c[0], currentPoint.y);
currentPoint.x = controlPoint.x = c[0];
controlPoint.y = currentPoint.y;
break;
case 'V':
case 'v':
if(!parseNumberList(ptr, end, c + 1, 1))
return path;
if(command == 'v')
c[1] += currentPoint.y;
path.lineTo(currentPoint.x, c[1]);
controlPoint.x = currentPoint.x;
currentPoint.y = controlPoint.y = c[1];
break;
case 'A':
case 'a':
if(!parseNumberList(ptr, end, c, 3) if(!parseNumberList(ptr, end, c, 3)
|| !parseArcFlag(ptr, end, f[0]) || !parseArcFlag(ptr, end, f[0])
|| !parseArcFlag(ptr, end, f[1]) || !parseArcFlag(ptr, end, f[1])
@ -335,16 +328,13 @@ Path Parser::parsePath(const std::string& string)
} }
path.arcTo(currentPoint.x, currentPoint.y, c[0], c[1], c[2], f[0], f[1], c[3], c[4]); path.arcTo(currentPoint.x, currentPoint.y, c[0], c[1], c[2], f[0], f[1], c[3], c[4]);
currentPoint.x = controlPoint.x = c[3]; currentPoint.x = c[3];
currentPoint.y = controlPoint.y = c[4]; currentPoint.y = c[4];
break; } else if(command == 'Z' || command == 'z') {
case 'Z':
case 'z':
path.close(); path.close();
currentPoint.x = controlPoint.x = startPoint.x; currentPoint.x = startPoint.x;
currentPoint.y = controlPoint.y = startPoint.y; currentPoint.y = startPoint.y;
break; } else {
default:
return path; return path;
} }
@ -352,6 +342,7 @@ Path Parser::parsePath(const std::string& string)
if(ptr >= end) if(ptr >= end)
break; break;
lastCommand = command;
if(IS_ALPHA(*ptr)) if(IS_ALPHA(*ptr))
command = *ptr++; command = *ptr++;
} }

View file

@ -77,6 +77,12 @@ std::unique_ptr<LayoutSymbol> SVGElement::build(const TreeBuilder* builder) cons
root->masker = context.getMasker(mask()); root->masker = context.getMasker(mask());
root->clipper = context.getClipper(clip_path()); root->clipper = context.getClipper(clip_path());
layoutChildren(&context, root.get()); layoutChildren(&context, root.get());
if((w.isRelative() || h.isRelative()) && !has(PropertyID::ViewBox)) {
auto box = root->map(root->strokeBoundingBox());
root->width = w.value(box.x + box.w);
root->height = h.value(box.y + box.h);
}
return root; return root;
} }