File indexing completed on 2024-06-09 04:23:51
0001 /* 0002 * SPDX-FileCopyrightText: 2015 Dmitry Kazakov <dimula73@gmail.com> 0003 * 0004 * SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include "kis_asl_xml_parser.h" 0008 0009 #include <stdexcept> 0010 #include <string> 0011 0012 #include <QBuffer> 0013 #include <QDomDocument> 0014 #include <QIODevice> 0015 #include <QFileInfo> 0016 0017 #include <QColor> 0018 #include <QHash> 0019 0020 #include <KoColorSpaceRegistry.h> 0021 #include <KoColorConversions.h> 0022 #include <resources/KoSegmentGradient.h> 0023 0024 #include "kis_dom_utils.h" 0025 0026 #include "compression.h" 0027 #include "kis_debug.h" 0028 #include "psd.h" 0029 #include "psd_utils.h" 0030 0031 #include "kis_asl_object_catcher.h" 0032 0033 namespace Private 0034 { 0035 void parseElement(const QDomElement &el, const QString &parentPath, KisAslObjectCatcher &catcher); 0036 0037 class CurveObjectCatcher : public KisAslObjectCatcher 0038 { 0039 public: 0040 void addText(const QString &path, const QString &value) override 0041 { 0042 if (path == "/Nm ") { 0043 m_name = value; 0044 } else { 0045 warnKrita << "XML (ASL): failed to parse curve object" << path << value; 0046 } 0047 } 0048 0049 void addPoint(const QString &path, const QPointF &value) override 0050 { 0051 if (!m_arrayMode) { 0052 warnKrita << "XML (ASL): failed to parse curve object (array fault)" << path << value << ppVar(m_arrayMode); 0053 } 0054 0055 m_points.append(value); 0056 } 0057 0058 public: 0059 QVector<QPointF> m_points; 0060 QString m_name; 0061 }; 0062 0063 KoColor parseColorObject(QDomElement parent, QString classID) 0064 { 0065 KoColor color; 0066 KoColor error = KoColor::fromXML("<color channeldepth='U8'><sRGB r='1.0' g='0.0' b='0.0'/></color>"); 0067 QDomDocument doc; 0068 QDomElement root; 0069 QString spotBook; 0070 QString spotName; 0071 int spotValue = 0; 0072 double h = 0; 0073 double s = 0; 0074 double v= 0; 0075 0076 if (classID == "RGBC" || classID == "HSBC") { 0077 color = KoColor(KoColorSpaceRegistry::instance()->rgb8()); 0078 root = doc.createElement("sRGB"); 0079 } else if (classID == "CMYC") { 0080 root = doc.createElement("CMYK"); 0081 } else if (classID == "LbCl") { 0082 root = doc.createElement("Lab"); 0083 } else if (classID == "Grsc") { 0084 root = doc.createElement("Gray"); 0085 } else { 0086 // Can be 'UnsC', or something else. 0087 warnKrita << "Unknown color type:" << ppVar(classID); 0088 return error; 0089 } 0090 0091 QDomNode child = parent.firstChild(); 0092 while (!child.isNull()) { 0093 QDomElement childEl = child.toElement(); 0094 0095 QString type = childEl.attribute("type", "<unknown>"); 0096 QString key = childEl.attribute("key", ""); 0097 0098 if (type == "Double" || type == "UnitFloat") { 0099 if (classID == "RGBC") { 0100 // For RGBC we'll just directly write to the KoColor data, to have as 0101 // few rounding errors possible. 0102 double value = KisDomUtils::toDouble(childEl.attribute("value", "0")); 0103 0104 if (key == "Rd ") { 0105 color.data()[2] = value; 0106 } else if (key == "Grn ") { 0107 color.data()[1] = value; 0108 } else if (key == "Bl ") { 0109 color.data()[0] = value; 0110 } else { 0111 warnKrita << "Unknown color key value double:" << ppVar(key); 0112 return error; 0113 } 0114 } else if (classID == "CMYC") { 0115 double value = KisDomUtils::toDouble(childEl.attribute("value", "0")) * 0.01; 0116 // CMYK is stored in percentages... 0117 if (key == "Cyn ") { 0118 root.setAttribute("c", value); 0119 } else if (key == "Mgnt") { 0120 root.setAttribute("m", value); 0121 } else if (key == "Ylw ") { 0122 root.setAttribute("y", value); 0123 } else if (key == "Blck") { 0124 root.setAttribute("k", value); 0125 } else { 0126 warnKrita << "Unknown color key value double:" << ppVar(key); 0127 return error; 0128 } 0129 } else if (classID == "LbCl") { 0130 if (key == "Lmnc") { 0131 root.setAttribute("L", childEl.attribute("value", "0")); 0132 } else if (key == "A ") { 0133 root.setAttribute("a", childEl.attribute("value", "0")); 0134 } else if (key == "B ") { 0135 root.setAttribute("b", childEl.attribute("value", "0")); 0136 } else { 0137 warnKrita << "Unknown color key value:" << ppVar(key); 0138 return error; 0139 } 0140 } else if (classID == "Grsc") { 0141 // Unsure that grey is stored as a percentage, might also be 255. 0142 double value = KisDomUtils::toDouble(childEl.attribute("value", "0")) * 0.01; 0143 if (key == "Gry ") { 0144 root.setAttribute("g", value); 0145 } else { 0146 warnKrita << "Unknown color key value:" << ppVar(key); 0147 return error; 0148 } 0149 } else if (classID == "HSBC") { 0150 double value = KisDomUtils::toDouble(childEl.attribute("value", "0")); 0151 if (key == "H ") { 0152 h = value; 0153 } else if (key == "Strt") { 0154 s = value * 0.01; 0155 } else if (key == "Brgh") { 0156 v = value * 0.01; 0157 } else { 0158 warnKrita << "Unknown color key value:" << ppVar(key); 0159 return error; 0160 } 0161 } 0162 } else if (type == "Text") { 0163 if (key== "Bk ") { 0164 spotBook = childEl.attribute("value", ""); 0165 } else if (key== "Nm ") { 0166 spotName = childEl.attribute("value", ""); 0167 } else { 0168 warnKrita << "Unknown color key value string:" << ppVar(key); 0169 } 0170 } else if (type == "Integer") { 0171 if (key== "bookID") { 0172 spotValue = KisDomUtils::toInt(childEl.attribute("value", "0")); 0173 } else { 0174 warnKrita << "Unknown color key value integer:" << ppVar(key); 0175 } 0176 } else { 0177 qDebug() << "Unknown color component type:" << ppVar(type) << ppVar(key); 0178 return error; 0179 } 0180 0181 child = child.nextSibling(); 0182 } 0183 if (classID == "HSBC") { 0184 float r = 0.0; 0185 float b = 0.0; 0186 float g = 0.0; 0187 HSVToRGB(h, s, v, &r, &g, &b); 0188 root.setAttribute("r", r); 0189 root.setAttribute("g", g); 0190 root.setAttribute("b", b); 0191 } 0192 if (classID != "RGBC") { 0193 color = KoColor::fromXML(root, "U8"); 0194 } 0195 color.setOpacity(OPACITY_OPAQUE_U8); 0196 if (!spotName.isEmpty()) { 0197 color.addMetadata("spotName", spotName); 0198 color.addMetadata("psdSpotBook", spotBook); 0199 color.addMetadata("psdSpotBookId", spotValue); 0200 } 0201 0202 return color; 0203 } 0204 0205 void parseColorStopsList(QDomElement parent, 0206 QVector<qreal> &startLocations, 0207 QVector<qreal> &middleOffsets, 0208 QVector<KoColor> &colors, 0209 QVector<KoGradientSegmentEndpointType> &types) 0210 { 0211 QDomNode child = parent.firstChild(); 0212 while (!child.isNull()) { 0213 QDomElement childEl = child.toElement(); 0214 0215 QString type = childEl.attribute("type", "<unknown>"); 0216 QString key = childEl.attribute("key", ""); 0217 QString classId = childEl.attribute("classId", ""); 0218 0219 if (type == "Descriptor" && classId == "Clrt") { 0220 // sorry for naming... 0221 QDomNode child = childEl.firstChild(); 0222 while (!child.isNull()) { 0223 QDomElement childEl = child.toElement(); 0224 0225 QString type = childEl.attribute("type", "<unknown>"); 0226 QString key = childEl.attribute("key", ""); 0227 QString classId = childEl.attribute("classId", ""); 0228 0229 if (type == "Integer" && key == "Lctn") { 0230 int value = KisDomUtils::toInt(childEl.attribute("value", "0")); 0231 startLocations.append(qreal(value) / 4096.0); 0232 0233 } else if (type == "Integer" && key == "Mdpn") { 0234 int value = KisDomUtils::toInt(childEl.attribute("value", "0")); 0235 middleOffsets.append(qreal(value) / 100.0); 0236 0237 } else if (type == "Descriptor" && key == "Clr ") { 0238 colors.append(parseColorObject(childEl, classId)); 0239 0240 } else if (type == "Enum" && key == "Type") { 0241 QString typeId = childEl.attribute("typeId", ""); 0242 0243 if (typeId != "Clry") { 0244 warnKrita << "WARNING: Invalid typeId of a gradient stop type" << typeId; 0245 } 0246 0247 QString value = childEl.attribute("value", ""); 0248 if (value == "BckC") { 0249 types.append(BACKGROUND_ENDPOINT); 0250 } else if (value == "FrgC") { 0251 types.append(FOREGROUND_ENDPOINT); 0252 } else { 0253 types.append(COLOR_ENDPOINT); 0254 } 0255 } 0256 0257 child = child.nextSibling(); 0258 } 0259 } else { 0260 warnKrita << "WARNING: Unrecognized object in color stops list" << ppVar(type) << ppVar(key) << ppVar(classId); 0261 } 0262 0263 child = child.nextSibling(); 0264 } 0265 } 0266 0267 void parseTransparencyStopsList(QDomElement parent, QVector<qreal> &startLocations, QVector<qreal> &middleOffsets, QVector<qreal> &transparencies) 0268 { 0269 QDomNode child = parent.firstChild(); 0270 while (!child.isNull()) { 0271 QDomElement childEl = child.toElement(); 0272 0273 QString type = childEl.attribute("type", "<unknown>"); 0274 QString key = childEl.attribute("key", ""); 0275 QString classId = childEl.attribute("classId", ""); 0276 0277 if (type == "Descriptor" && classId == "TrnS") { 0278 // sorry for naming again... 0279 QDomNode child = childEl.firstChild(); 0280 while (!child.isNull()) { 0281 QDomElement childEl = child.toElement(); 0282 0283 QString type = childEl.attribute("type", "<unknown>"); 0284 QString key = childEl.attribute("key", ""); 0285 0286 if (type == "Integer" && key == "Lctn") { 0287 int value = KisDomUtils::toInt(childEl.attribute("value", "0")); 0288 startLocations.append(qreal(value) / 4096.0); 0289 } else if (type == "Integer" && key == "Mdpn") { 0290 int value = KisDomUtils::toInt(childEl.attribute("value", "0")); 0291 middleOffsets.append(qreal(value) / 100.0); 0292 } else if (type == "UnitFloat" && key == "Opct") { 0293 QString unit = childEl.attribute("unit", ""); 0294 if (unit != "#Prc") { 0295 warnKrita << "WARNING: Invalid unit of a gradient stop transparency" << unit; 0296 } 0297 0298 qreal value = KisDomUtils::toDouble(childEl.attribute("value", "100")); 0299 transparencies.append(value / 100.0); 0300 } 0301 0302 child = child.nextSibling(); 0303 } 0304 0305 } else { 0306 warnKrita << "WARNING: Unrecognized object in transparency stops list" << ppVar(type) << ppVar(key) << ppVar(classId); 0307 } 0308 0309 child = child.nextSibling(); 0310 } 0311 } 0312 0313 inline QString buildPath(const QString &parent, const QString &key) 0314 { 0315 return parent + "/" + key; 0316 } 0317 0318 bool tryParseDescriptor(const QDomElement &el, const QString &path, const QString &classId, KisAslObjectCatcher &catcher) 0319 { 0320 bool retval = true; 0321 0322 if (classId == "null") { 0323 catcher.newStyleStarted(); 0324 // here we just notify that a new style is started, we haven't 0325 // processed the whole block yet, so return false. 0326 retval = false; 0327 } else if (el.attribute("key", " ") == "Clr ") { 0328 catcher.addColor(path, parseColorObject(el, classId)); 0329 } else if (el.attribute("key", " ") == "hglC" || el.attribute("key", " ") == "sdwC") { 0330 // like Clr, but /ebbl/ likes to do everything differently - see bug 464218 0331 catcher.addColor(path, parseColorObject(el, classId)); 0332 } else if (classId == "ShpC") { 0333 CurveObjectCatcher curveCatcher; 0334 0335 QDomNode child = el.firstChild(); 0336 while (!child.isNull()) { 0337 parseElement(child.toElement(), "", curveCatcher); 0338 child = child.nextSibling(); 0339 } 0340 0341 catcher.addCurve(path, curveCatcher.m_name, curveCatcher.m_points); 0342 0343 } else if (classId == "CrPt") { 0344 QPointF point; 0345 0346 QDomNode child = el.firstChild(); 0347 while (!child.isNull()) { 0348 QDomElement childEl = child.toElement(); 0349 0350 QString type = childEl.attribute("type", "<unknown>"); 0351 QString key = childEl.attribute("key", ""); 0352 0353 if (type == "Boolean" && key == "Cnty") { 0354 warnKrita << "WARNING: tryParseDescriptor: The points of the curve object contain \'Cnty\' flag which is unsupported by Krita"; 0355 warnKrita << " " << ppVar(type) << ppVar(key) << ppVar(path); 0356 0357 child = child.nextSibling(); 0358 continue; 0359 } 0360 0361 if (type != "Double") { 0362 warnKrita << "Unknown point component type:" << ppVar(type) << ppVar(key) << ppVar(path); 0363 return false; 0364 } 0365 0366 double value = KisDomUtils::toDouble(childEl.attribute("value", "0")); 0367 0368 if (key == "Hrzn") { 0369 point.setX(value); 0370 } else if (key == "Vrtc") { 0371 point.setY(value); 0372 } else { 0373 warnKrita << "Unknown point key value:" << ppVar(key) << ppVar(path); 0374 return false; 0375 } 0376 0377 child = child.nextSibling(); 0378 } 0379 0380 catcher.addPoint(path, point); 0381 0382 } else if (classId == "Pnt ") { 0383 QPointF point; 0384 0385 QDomNode child = el.firstChild(); 0386 while (!child.isNull()) { 0387 QDomElement childEl = child.toElement(); 0388 0389 QString type = childEl.attribute("type", "<unknown>"); 0390 QString key = childEl.attribute("key", ""); 0391 QString unit = childEl.attribute("unit", ""); 0392 0393 if (type != "Double" && !(type == "UnitFloat" && unit == "#Prc")) { 0394 warnKrita << "Unknown point component type:" << ppVar(unit) << ppVar(type) << ppVar(key) << ppVar(path); 0395 return false; 0396 } 0397 0398 double value = KisDomUtils::toDouble(childEl.attribute("value", "0")); 0399 0400 if (key == "Hrzn") { 0401 point.setX(value); 0402 } else if (key == "Vrtc") { 0403 point.setY(value); 0404 } else { 0405 warnKrita << "Unknown point key value:" << ppVar(key) << ppVar(path); 0406 return false; 0407 } 0408 0409 child = child.nextSibling(); 0410 } 0411 0412 catcher.addPoint(path, point); 0413 0414 } else if (classId == "KisPattern") { 0415 QByteArray patternData; 0416 QString patternUuid; 0417 0418 QDomNode child = el.firstChild(); 0419 while (!child.isNull()) { 0420 QDomElement childEl = child.toElement(); 0421 0422 QString type = childEl.attribute("type", "<unknown>"); 0423 QString key = childEl.attribute("key", ""); 0424 0425 if (type == "Text" && key == "Idnt") { 0426 patternUuid = childEl.attribute("value", "").trimmed(); 0427 } 0428 0429 if (type == "KisPatternData" && key == "Data") { 0430 QDomNode dataNode = child.firstChild(); 0431 0432 if (!dataNode.isCDATASection()) { 0433 warnKrita << "WARNING: failed to parse KisPatternData XML section!"; 0434 continue; 0435 } 0436 0437 QDomCDATASection dataSection = dataNode.toCDATASection(); 0438 QByteArray data = dataSection.data().toLatin1(); 0439 data = QByteArray::fromBase64(data); 0440 data = qUncompress(data); 0441 0442 if (data.isEmpty()) { 0443 warnKrita << "WARNING: failed to parse KisPatternData XML section!"; 0444 continue; 0445 } 0446 0447 patternData = data; 0448 } 0449 0450 child = child.nextSibling(); 0451 } 0452 0453 if (!patternUuid.isEmpty() && !patternData.isEmpty()) { 0454 QString fileName = QString("%1.pat").arg(patternUuid); 0455 0456 QSharedPointer<KoPattern> pattern(new KoPattern(fileName)); 0457 0458 QBuffer buffer(&patternData); 0459 buffer.open(QIODevice::ReadOnly); 0460 0461 if (pattern->loadPatFromDevice(&buffer) && pattern->valid()) { 0462 catcher.addPattern(path, pattern, patternUuid); 0463 } 0464 else { 0465 warnKrita << "WARNING: failed to create pattern:" << ppVar(patternUuid) << ppVar(pattern); 0466 } 0467 } else { 0468 warnKrita << "WARNING: failed to load KisPattern XML section!" << ppVar(patternUuid); 0469 } 0470 0471 } else if (classId == "Ptrn") { // reference to an existing pattern 0472 QString patternUuid; 0473 QString patternName; 0474 0475 QDomNode child = el.firstChild(); 0476 while (!child.isNull()) { 0477 QDomElement childEl = child.toElement(); 0478 0479 QString type = childEl.attribute("type", "<unknown>"); 0480 QString key = childEl.attribute("key", ""); 0481 0482 if (type == "Text" && key == "Idnt") { 0483 patternUuid = childEl.attribute("value", ""); 0484 } else if (type == "Text" && key == "Nm ") { 0485 patternName = childEl.attribute("value", ""); 0486 } else { 0487 warnKrita << "WARNING: unrecognized pattern-ref section key:" << ppVar(type) << ppVar(key); 0488 } 0489 0490 child = child.nextSibling(); 0491 } 0492 0493 catcher.addPatternRef(path, patternUuid, patternName); 0494 0495 } else if (classId == "Grdn") { 0496 QString gradientName; 0497 qreal gradientSmoothness = 100.0; 0498 0499 QVector<qreal> startLocations; 0500 QVector<qreal> middleOffsets; 0501 QVector<KoColor> colors; 0502 QVector<KoGradientSegmentEndpointType> types; 0503 0504 QVector<qreal> transpStartLocations; 0505 QVector<qreal> transpMiddleOffsets; 0506 QVector<qreal> transparencies; 0507 0508 QDomNode child = el.firstChild(); 0509 while (!child.isNull()) { 0510 QDomElement childEl = child.toElement(); 0511 0512 QString type = childEl.attribute("type", "<unknown>"); 0513 QString key = childEl.attribute("key", ""); 0514 0515 if (type == "Text" && key == "Nm ") { 0516 gradientName = childEl.attribute("value", ""); 0517 } else if (type == "Enum" && key == "GrdF") { 0518 QString typeId = childEl.attribute("typeId", ""); 0519 QString value = childEl.attribute("value", ""); 0520 0521 if (typeId != "GrdF" || value != "CstS") { 0522 warnKrita << "WARNING: Unsupported gradient type (probably, noise-based):" << value; 0523 return true; 0524 } 0525 } else if (type == "Double" && key == "Intr") { 0526 double value = KisDomUtils::toDouble(childEl.attribute("value", "4096")); 0527 gradientSmoothness = 100.0 * value / 4096.0; 0528 } else if (type == "List" && key == "Clrs") { 0529 parseColorStopsList(childEl, startLocations, middleOffsets, colors, types); 0530 } else if (type == "List" && key == "Trns") { 0531 parseTransparencyStopsList(childEl, transpStartLocations, transpMiddleOffsets, transparencies); 0532 } 0533 0534 child = child.nextSibling(); 0535 } 0536 0537 if (colors.size() < transparencies.size()) { 0538 const KoColor lastColor = !colors.isEmpty() ? colors.last() : KoColor(); 0539 const KoGradientSegmentEndpointType lastType = !types.isEmpty() ? types.last() : COLOR_ENDPOINT; 0540 while (colors.size() != transparencies.size()) { 0541 const int index = colors.size(); 0542 colors.append(lastColor); 0543 startLocations.append(transpStartLocations[index]); 0544 middleOffsets.append(transpMiddleOffsets[index]); 0545 types.append(lastType); 0546 } 0547 } 0548 0549 if (colors.size() > transparencies.size()) { 0550 const qreal lastTransparency = !transparencies.isEmpty() ? transparencies.last() : 1.0; 0551 while (colors.size() != transparencies.size()) { 0552 const int index = transparencies.size(); 0553 transparencies.append(lastTransparency); 0554 transpStartLocations.append(startLocations[index]); 0555 transpMiddleOffsets.append(middleOffsets[index]); 0556 } 0557 } 0558 0559 if (colors.size() == 1) { 0560 colors.append(colors.last()); 0561 startLocations.append(1.0); 0562 middleOffsets.append(0.5); 0563 types.append(COLOR_ENDPOINT); 0564 0565 transparencies.append(transparencies.last()); 0566 transpStartLocations.append(1.0); 0567 transpMiddleOffsets.append(0.5); 0568 } 0569 0570 /** 0571 * Filenames in Krita cannot have slashes inside, but some of the 0572 * styles saved in 4.x days could have that. Here we just forcefully 0573 * crop the directory part of the gradient to make sure that it fits 0574 * the new policy. 0575 * 0576 * Since ASL doesn't use this name as any linkage (actually, gradients 0577 * are always embedded into the style) so we don't really care about 0578 * the contents of the filename field. It should just be somewhat unique. 0579 */ 0580 const QString fileName = QFileInfo(gradientName).fileName() + ".ggr"; 0581 QSharedPointer<KoSegmentGradient> gradient(new KoSegmentGradient(fileName)); 0582 Q_UNUSED(gradientSmoothness); 0583 gradient->setName(gradientName); 0584 0585 if (colors.size() >= 2) { 0586 for (int i = 1; i < colors.size(); i++) { 0587 KoColor startColor = colors[i - 1]; 0588 KoColor endColor = colors[i]; 0589 startColor.setOpacity(transparencies[i - 1]); 0590 endColor.setOpacity(transparencies[i]); 0591 0592 qreal start = startLocations[i - 1]; 0593 qreal end = startLocations[i]; 0594 qreal middle = start + middleOffsets[i - 1] * (end - start); 0595 0596 KoGradientSegmentEndpointType startType = types[i - 1]; 0597 KoGradientSegmentEndpointType endType = types[i]; 0598 0599 gradient->createSegment(INTERP_LINEAR, COLOR_INTERP_RGB, start, end, middle, startColor, endColor, startType, endType); 0600 } 0601 gradient->setValid(true); 0602 gradient->updatePreview(); 0603 } else { 0604 gradient->setValid(false); 0605 } 0606 0607 catcher.addGradient(path, gradient); 0608 } else { 0609 retval = false; 0610 } 0611 0612 return retval; 0613 } 0614 0615 void parseElement(const QDomElement &el, const QString &parentPath, KisAslObjectCatcher &catcher) 0616 { 0617 KIS_ASSERT_RECOVER_RETURN(el.tagName() == "node"); 0618 0619 QString type = el.attribute("type", "<unknown>"); 0620 QString key = el.attribute("key", ""); 0621 0622 if (type == "Descriptor") { 0623 QString classId = el.attribute("classId", "<noClassId>"); 0624 QString containerName = key.isEmpty() ? classId : key; 0625 QString containerPath = buildPath(parentPath, containerName); 0626 0627 if (!tryParseDescriptor(el, containerPath, classId, catcher)) { 0628 QDomNode child = el.firstChild(); 0629 while (!child.isNull()) { 0630 parseElement(child.toElement(), containerPath, catcher); 0631 child = child.nextSibling(); 0632 } 0633 } 0634 } else if (type == "List") { 0635 catcher.setArrayMode(true); 0636 0637 QString containerName = key; 0638 QString containerPath = buildPath(parentPath, containerName); 0639 0640 QDomNode child = el.firstChild(); 0641 while (!child.isNull()) { 0642 parseElement(child.toElement(), containerPath, catcher); 0643 child = child.nextSibling(); 0644 } 0645 0646 catcher.setArrayMode(false); 0647 } else if (type == "Double") { 0648 double v = KisDomUtils::toDouble(el.attribute("value", "0")); 0649 catcher.addDouble(buildPath(parentPath, key), v); 0650 } else if (type == "UnitFloat") { 0651 QString unit = el.attribute("unit", "<unknown>"); 0652 double v = KisDomUtils::toDouble(el.attribute("value", "0")); 0653 catcher.addUnitFloat(buildPath(parentPath, key), unit, v); 0654 } else if (type == "Text") { 0655 QString v = el.attribute("value", ""); 0656 catcher.addText(buildPath(parentPath, key), v); 0657 } else if (type == "Enum") { 0658 QString v = el.attribute("value", ""); 0659 QString typeId = el.attribute("typeId", "<unknown>"); 0660 catcher.addEnum(buildPath(parentPath, key), typeId, v); 0661 } else if (type == "Integer") { 0662 int v = KisDomUtils::toInt(el.attribute("value", "0")); 0663 catcher.addInteger(buildPath(parentPath, key), v); 0664 } else if (type == "Boolean") { 0665 int v = KisDomUtils::toInt(el.attribute("value", "0")); 0666 catcher.addBoolean(buildPath(parentPath, key), v); 0667 } else { 0668 warnKrita << "WARNING: XML (ASL) Unknown element type:" << type << ppVar(parentPath) << ppVar(key); 0669 } 0670 } 0671 0672 } // namespace 0673 0674 void KisAslXmlParser::parseXML(const QDomDocument &doc, KisAslObjectCatcher &catcher) 0675 { 0676 QDomElement root = doc.documentElement(); 0677 if (root.tagName() != "asl") { 0678 return; 0679 } 0680 0681 QDomNode child = root.firstChild(); 0682 while (!child.isNull()) { 0683 Private::parseElement(child.toElement(), "", catcher); 0684 child = child.nextSibling(); 0685 } 0686 }