diff --git a/inc/thorvg.h b/inc/thorvg.h index a4ca04d8..2620967f 100644 --- a/inc/thorvg.h +++ b/inc/thorvg.h @@ -50,7 +50,7 @@ protected: \ friend Canvas; \ friend Scene; \ friend Picture; \ - friend SaveModule; \ + friend IteratorModule; \ #define _TVG_DECALRE_IDENTIFIER() \ @@ -62,6 +62,7 @@ namespace tvg { class RenderMethod; +class IteratorModule; class SaveModule; class Scene; class Picture; diff --git a/src/lib/meson.build b/src/lib/meson.build index ee2992c3..a6d4cff2 100644 --- a/src/lib/meson.build +++ b/src/lib/meson.build @@ -19,6 +19,7 @@ source_file = [ 'tvgLzw.h', 'tvgPictureImpl.h', 'tvgRender.h', + 'tvgIteratorModule.h', 'tvgSaveModule.h', 'tvgSceneImpl.h', 'tvgShapeImpl.h', diff --git a/src/lib/tvgIteratorModule.h b/src/lib/tvgIteratorModule.h new file mode 100644 index 00000000..c54063ea --- /dev/null +++ b/src/lib/tvgIteratorModule.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2021 Samsung Electronics Co., Ltd. All rights reserved. + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#ifndef _TVG_ITERATOR_MODULE_H_ +#define _TVG_ITERATOR_MODULE_H_ + +#include "tvgPaint.h" + +namespace tvg +{ + +class IteratorModule +{ +public: + //Utility Method: Iterator Delegator + Iterator* iterator(const Paint* paint) + { + return paint->pImpl->iterator(); + } +}; + +} + +#endif //_TVG_ITERATOR_MODULE_H_ diff --git a/src/lib/tvgSaveModule.h b/src/lib/tvgSaveModule.h index 6342670b..6a980bde 100644 --- a/src/lib/tvgSaveModule.h +++ b/src/lib/tvgSaveModule.h @@ -22,26 +22,20 @@ #ifndef _TVG_SAVE_MODULE_H_ #define _TVG_SAVE_MODULE_H_ -#include "tvgPaint.h" +#include "tvgIteratorModule.h" namespace tvg { -class SaveModule +class SaveModule : public IteratorModule { public: virtual ~SaveModule() {} virtual bool save(Paint* paint, const string& path, bool compress) = 0; virtual bool close() = 0; - - //Utility Method: Iterator Delegator - Iterator* iterator(const Paint* paint) - { - return paint->pImpl->iterator(); - } }; } -#endif //_TVG_SAVE_MODULE_H_ \ No newline at end of file +#endif //_TVG_SAVE_MODULE_H_ diff --git a/src/meson.build b/src/meson.build index 7dbadd93..def8c48c 100644 --- a/src/meson.build +++ b/src/meson.build @@ -40,12 +40,12 @@ thorvg_dep = declare_dependency( ) if (cc.get_id() == 'emscripten') - subdir('wasm') executable('thorvg-wasm', - [], - dependencies : [thorvg_dep, thorvg_wasm_dep], + [], + include_directories : headers, + dependencies : [thorvg_lib_dep, thorvg_wasm_dep], ) endif diff --git a/src/wasm/thorvgwasm.cpp b/src/wasm/thorvgwasm.cpp index 3a59a204..88352a5f 100644 --- a/src/wasm/thorvgwasm.cpp +++ b/src/wasm/thorvgwasm.cpp @@ -21,6 +21,7 @@ */ #include +#include "tvgIteratorModule.h" #include @@ -30,7 +31,7 @@ using namespace tvg; string defaultData(""); -class __attribute__((visibility("default"))) ThorvgWasm +class __attribute__((visibility("default"))) ThorvgWasm : public IteratorModule { public: static unique_ptr create() @@ -157,6 +158,47 @@ public: return true; } + val layers() + { + //returns an array of a structure Layer: [id] [depth] [type] [composite] + mLayers.reset(); + sublayers(&mLayers, mPicture, 0); + + return val(typed_memory_view(mLayers.count * sizeof(Layer) / sizeof(uint32_t), (uint32_t *)(mLayers.data))); + } + + bool setOpacity(uint32_t paintId, uint8_t opacity) + { + const Paint* paint = findPaintById(mPicture, paintId, nullptr); + if (!paint) return false; + const_cast(paint)->opacity(opacity); + return true; + } + + val bounds(uint32_t paintId) + { + Array parents; + const Paint* paint = findPaintById(mPicture, paintId, &parents); + if (!paint) return val(typed_memory_view(0, nullptr)); + paint->bounds(&mBounds[0], &mBounds[1], &mBounds[2], &mBounds[3]); + + mBounds[2] += mBounds[0]; + mBounds[3] += mBounds[1]; + + for (auto paint = parents.data; paint < (parents.data + parents.count); ++paint) { + auto m = const_cast(*paint)->transform(); + mBounds[0] = mBounds[0] * m.e11 + m.e13; + mBounds[1] = mBounds[1] * m.e22 + m.e23; + mBounds[2] = mBounds[2] * m.e11 + m.e13; + mBounds[3] = mBounds[3] * m.e22 + m.e23; + } + + mBounds[2] -= mBounds[0]; + mBounds[3] -= mBounds[1]; + + return val(typed_memory_view(4, mBounds)); + } + private: explicit ThorvgWasm() { @@ -183,6 +225,69 @@ private: if (mPicture) mPicture->size(width, height); } + struct Layer + { + uint32_t paint; //cast of a paint pointer + uint32_t depth; + uint32_t type; + uint32_t composite; + }; + void sublayers(Array* layers, const Paint* paint, uint32_t depth) + { + //paint + if (paint->id() != TVG_CLASS_ID_SHAPE) { + auto it = this->iterator(paint); + if (it->count() > 0) { + layers->reserve(layers->count + it->count()); + it->begin(); + while (auto child = it->next()) { + uint32_t type = child->id(); + layers->push({.paint = reinterpret_cast(child), .depth = depth + 1, .type = type, .composite = static_cast(CompositeMethod::None)}); + sublayers(layers, child, depth + 1); + } + } + } + //composite + const Paint* compositeTarget = nullptr; + CompositeMethod composite = paint->composite(&compositeTarget); + if (compositeTarget && composite != CompositeMethod::None) { + uint32_t type = compositeTarget->id(); + layers->push({.paint = reinterpret_cast(compositeTarget), .depth = depth, .type = type, .composite = static_cast(composite)}); + sublayers(layers, compositeTarget, depth); + } + } + + const Paint* findPaintById(const Paint* parent, uint32_t paintId, Array* parents) { + //validate paintId is correct and exists in the picture + if (reinterpret_cast(parent) == paintId) { + if (parents) parents->push(parent); + return parent; + } + //paint + if (parent->id() != TVG_CLASS_ID_SHAPE) { + auto it = this->iterator(parent); + if (it->count() > 0) { + it->begin(); + while (auto child = it->next()) { + if (auto paint = findPaintById(child, paintId, parents)) { + if (parents) parents->push(parent); + return paint; + } + } + } + } + //composite + const Paint* compositeTarget = nullptr; + CompositeMethod composite = parent->composite(&compositeTarget); + if (compositeTarget && composite != CompositeMethod::None) { + if (auto paint = findPaintById(compositeTarget, paintId, parents)) { + if (parents) parents->push(parent); + return paint; + } + } + return nullptr; + } + private: string mErrorMsg; unique_ptr< SwCanvas > mSwCanvas = nullptr; @@ -191,6 +296,9 @@ private: uint32_t mWidth{0}; uint32_t mHeight{0}; + + Array mLayers; + float mBounds[4]; float mOriginalSize[2]; }; @@ -205,5 +313,9 @@ EMSCRIPTEN_BINDINGS(thorvg_bindings) { .function("render", &ThorvgWasm::render) .function("originalSize", &ThorvgWasm::originalSize) - .function("saveTvg", &ThorvgWasm::saveTvg); + .function("saveTvg", &ThorvgWasm::saveTvg) + + .function("layers", &ThorvgWasm::layers) + .function("bounds", &ThorvgWasm::bounds) + .function("setOpacity", &ThorvgWasm::setOpacity); }