From a3358fee621ad6ef38ce66aa70e7263337210ea5 Mon Sep 17 00:00:00 2001 From: Matthew Woehlke Date: Wed, 28 Apr 2021 21:04:12 -0400 Subject: [PATCH 1/4] Fix SVG embedding Modify SPUse to use the referenced object's document when rebuilding its tree, rather than its own. For "regular" clones, these will be the same, but this is critical for correct rendering when embedding one SVG into another and is, more or less (see below), the correct behavior according to the specification. Also modify SPDocument::getObjectById to walk up the document tree looking for the object, as this is needed for the embedded SVG to be able to resolve references against the embedding document if they cannot be resolved "internally". (So far as I can tell, this is the correct behavior according to the specification.) As I understand the specification, this implementation is technically non-conforming, because it will resolve references *anywhere* in the embedded document, not just within the selected subtree. However, a) from my (admittedly limited) understanding of the code, I believe it is somewhat challenging to implement this strictly according to the spec, and would meanwhile like it to be less broken, and b) I suspect this behavior is actually more *useful* anyway. This does cause a problem with application of CSS rules, in that the embedding document's rules are no longer applied. This will be fixed in a subsequent commit. Fixes https://gitlab.com/inkscape/inkscape/-/issues/1757. --- src/document.cpp | 2 ++ src/object/sp-use.cpp | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/document.cpp b/src/document.cpp index 9e6fd7efbf..ffd3556cad 100644 --- a/src/document.cpp +++ b/src/document.cpp @@ -1051,6 +1051,8 @@ SPObject *SPDocument::getObjectById(Glib::ustring const &id) const std::map::const_iterator rv = iddef.find(id); if (rv != iddef.end()) { return (rv->second); + } else if (_parent_document) { + return _parent_document->getObjectById(id); } else { return nullptr; } diff --git a/src/object/sp-use.cpp b/src/object/sp-use.cpp index d29060ef94..d7ac8146b5 100644 --- a/src/object/sp-use.cpp +++ b/src/object/sp-use.cpp @@ -524,7 +524,7 @@ void SPUse::href_changed() { this->attach(this->child, this->lastChild()); sp_object_unref(this->child, this); - this->child->invoke_build(this->document, childrepr, TRUE); + this->child->invoke_build(refobj->document, childrepr, TRUE); for (SPItemView *v = this->display; v != nullptr; v = v->next) { Inkscape::DrawingItem *ai = this->child->invoke_show(v->arenaitem->drawing(), v->key, v->flags); -- GitLab From a8be52618ebd25ffef2c89a6026588e0e754613f Mon Sep 17 00:00:00 2001 From: Matthew Woehlke Date: Wed, 28 Apr 2021 21:17:00 -0400 Subject: [PATCH 2/4] Resolve CSS up the document tree Modify SPStyle::_mergeObjectStylesheet to walk up the document tree when applying CSS, with rules applied from most ancestral to most proximate. This is necessary to correctly resolve CSS styling for embedded SVGs, as mentioned in the previous commit. --- src/document.h | 3 +++ src/style.cpp | 15 +++++++++++---- src/style.h | 1 + 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/src/document.h b/src/document.h index c2c59aedb9..a04c19d1ec 100644 --- a/src/document.h +++ b/src/document.h @@ -194,6 +194,9 @@ public: std::vector getLanguages() const; + SPDocument *getParent() { return _parent_document; } + SPDocument const *getParent() const { return _parent_document; } + // Styling CRCascade *getStyleCascade() { return style_cascade; } diff --git a/src/style.cpp b/src/style.cpp index a96c89466b..8b17b329b1 100644 --- a/src/style.cpp +++ b/src/style.cpp @@ -996,9 +996,16 @@ SPStyle::_mergeObjectStylesheet( SPObject const *const object ) { // std::cout << "SPStyle::_mergeObjectStylesheet: " << (object->getId()?object->getId():"null") << std::endl; - static CRSelEng *sel_eng = nullptr; - if (!sel_eng) { - sel_eng = sp_repr_sel_eng(); + _mergeObjectStylesheet(object, object->document); +} + +void +SPStyle::_mergeObjectStylesheet( SPObject const *const object, SPDocument *const document ) { + + static CRSelEng *sel_eng = sp_repr_sel_eng(); + + if (auto *const parent = document->getParent()) { + _mergeObjectStylesheet(object, parent); } CRPropList *props = nullptr; @@ -1006,7 +1013,7 @@ SPStyle::_mergeObjectStylesheet( SPObject const *const object ) { //XML Tree being directly used here while it shouldn't be. CRStatus status = cr_sel_eng_get_matched_properties_from_cascade(sel_eng, - object->document->getStyleCascade(), + document->getStyleCascade(), object->getRepr(), &props); g_return_if_fail(status == CR_OK); diff --git a/src/style.h b/src/style.h index 121fc39e64..6a98bbc9e6 100644 --- a/src/style.h +++ b/src/style.h @@ -81,6 +81,7 @@ private: void _mergeDecl( CRDeclaration const *const decl, SPStyleSrc const &source ); void _mergeProps( CRPropList *const props ); void _mergeObjectStylesheet( SPObject const *const object ); + void _mergeObjectStylesheet( SPObject const *const object, SPDocument *const document ); private: int _refcount; -- GitLab From 0a9f9828b568e60ba6419ff38791581f98f10372 Mon Sep 17 00:00:00 2001 From: Matthew Woehlke Date: Thu, 29 Apr 2021 19:38:33 -0400 Subject: [PATCH 3/4] Add test for Add a test for proper rendering of SVGs embedded via , with particular focus on proper rendering of elements that reference other elements in the embedded SVG. This will serve to validate the issues addressed by the immediately preceding commits. --- testfiles/rendering_tests/CMakeLists.txt | 1 + .../expected_rendering/test-use-large.png | Bin 0 -> 6452 bytes .../expected_rendering/test-use.png | Bin 0 -> 1204 bytes testfiles/rendering_tests/test-use-ref.svg | 89 ++++++++++++++++++ testfiles/rendering_tests/test-use.svg | 18 ++++ 5 files changed, 108 insertions(+) create mode 100644 testfiles/rendering_tests/expected_rendering/test-use-large.png create mode 100644 testfiles/rendering_tests/expected_rendering/test-use.png create mode 100644 testfiles/rendering_tests/test-use-ref.svg create mode 100644 testfiles/rendering_tests/test-use.svg diff --git a/testfiles/rendering_tests/CMakeLists.txt b/testfiles/rendering_tests/CMakeLists.txt index 23a46ac7bf..b9c6f4dd5d 100644 --- a/testfiles/rendering_tests/CMakeLists.txt +++ b/testfiles/rendering_tests/CMakeLists.txt @@ -13,6 +13,7 @@ set(RENDERING_TESTS # -- Generic tests -- test-empty test-dont-crash + test-use # -- Selector tests -- selector-important-002 diff --git a/testfiles/rendering_tests/expected_rendering/test-use-large.png b/testfiles/rendering_tests/expected_rendering/test-use-large.png new file mode 100644 index 0000000000000000000000000000000000000000..c1f4597a33b560023dd691a2f6396fe0ef928dd8 GIT binary patch literal 6452 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 CxYd3D literal 0 HcmV?d00001 diff --git a/testfiles/rendering_tests/expected_rendering/test-use.png b/testfiles/rendering_tests/expected_rendering/test-use.png new file mode 100644 index 0000000000000000000000000000000000000000..a99513677cd3d11477b6f3628aa6fe9b41bf5850 GIT binary patch literal 1204 zcmeAS@N?(olHy`uVBq!ia0y~yU`PRB4mJh`hJr^^Ll_tsI14-?iy0XB4ude`@%$Aa z6_O>c5hcO-X(i=}MX3zs<>h*rdD+Fui3O>8`9|3G{vTV-~a^!i?8_G!i>7N#*c!ZzrEa>n6lsn5v|~$=Mt_Mf9K1vZ<%5HQxsBVk$de zCinKH^)5jv4wL6{s>y;utLB9+JMNW8;YkMsdTn zv30JK*fg!S9dP#fKIQfdHS2k%#mYxgW=t^speEx2Y%_i78f= zrUqR*&=z(=ZJDX2mx62i$%qSU7x~PXTVJTzxFI9s+vV_mda;TNEgooxMyfsGE$}q= zQgA)ax^m<9t2g@Urthph|KaKL$($|U53oN_f8hV%{_~1=-bPp7el^-7&^_t&46`Y% zH(onr-I0G(==qAtp1W}aV;zef(|)G=$G`txx^QJ2n@@OT<#zMwk5;cYja9VEzZ!l| z`Sj(36CW;mP#z^&{_ee@rg<5R(%IT(8R_|iDcQK6r{*lL`E6;rky=Gg${YU-J- zUmD~WUF5pmdKI;Vst E04J;_AOHXW literal 0 HcmV?d00001 diff --git a/testfiles/rendering_tests/test-use-ref.svg b/testfiles/rendering_tests/test-use-ref.svg new file mode 100644 index 0000000000..0e6edf3310 --- /dev/null +++ b/testfiles/rendering_tests/test-use-ref.svg @@ -0,0 +1,89 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/testfiles/rendering_tests/test-use.svg b/testfiles/rendering_tests/test-use.svg new file mode 100644 index 0000000000..7e8a8acdd0 --- /dev/null +++ b/testfiles/rendering_tests/test-use.svg @@ -0,0 +1,18 @@ + + + + + -- GitLab From 38092e10b72e0db2af08e875349af8cd4993f0e2 Mon Sep 17 00:00:00 2001 From: Matthew Woehlke Date: Sat, 1 May 2021 13:43:17 -0400 Subject: [PATCH 4/4] Fix languages of embedded SVG Also modify SPDocument::getLanguages to traverse up the document tree, much as SPDocument::getObjectById was modified recently, and for the same reason; this is needed to get the correct set of languages for an embedded SVG now that the trees for those are built based on the SPDocument of the embedded SVG rather than the embedding SPDocument. Co-authored-by: Thomas Holder --- src/document.cpp | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/document.cpp b/src/document.cpp index ffd3556cad..226a5a3324 100644 --- a/src/document.cpp +++ b/src/document.cpp @@ -1212,6 +1212,23 @@ std::vector SPDocument::getLanguages() const g_free(rdf_language_stripped); } + // add languages from parent document + if (_parent_document) { + auto parent_languages = _parent_document->getLanguages(); + + // return parent languages directly if we aren't contributing any + if (document_languages.empty()) { + return parent_languages; + } + + // otherwise append parent's languages to what we already have + std::move(parent_languages.begin(), parent_languages.end(), + std::back_insert_iterator(document_languages)); + + // don't add languages from locale; parent already did that + return document_languages; + } + // get language from system locale (will also match the interface language preference as we set LANG accordingly) // TODO: This includes locales with encodings like "de_DE.UTF-8" - is this useful or should we skip these? // TODO: This includes the default "C" locale - is this useful or should we skip it? -- GitLab