Commit 03c666e0 authored by RazrFalcon's avatar RazrFalcon

(c-api) Qt wrapper is header-only now.

parent cc0dcb69
......@@ -10,6 +10,9 @@ This changelog also contains an important changes in dependencies.
### Added
- (c-api) `RESVG_ERROR_PARSING_FAILED`.
### Changed
- (c-api) Qt wrapper is header-only now.
### Fixed
- (cairo-backend) Text layout.
- (resvg) Recursive SVG images via `image` tag.
......
......@@ -4,19 +4,32 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#include <ResvgQt.h>
/**
* @file ResvgQt.h
*
* Qt wrapper for resvg C-API
*/
#ifndef RESVGQT_H
#define RESVGQT_H
extern "C" {
#define RESVG_QT_BACKEND
extern "C" {
#include <resvg.h>
}
#include <QString>
#include <QScopedPointer>
#include <QRectF>
#include <QTransform>
#include <QGuiApplication>
#include <QScreen>
#include <QPainter>
#include <QFile>
#include <QDebug>
namespace ResvgPrivate {
static void initOptions(resvg_options &opt)
{
......@@ -29,10 +42,15 @@ static void initOptions(resvg_options &opt)
}
}
class ResvgRendererPrivate
class Data
{
public:
~ResvgRendererPrivate()
Data()
{
resvg_init_options(&opt);
}
~Data()
{
reset();
}
......@@ -84,26 +102,160 @@ static QString errorToString(const int err)
Q_UNREACHABLE();
}
ResvgRenderer::ResvgRenderer()
: d(new ResvgRendererPrivate())
} //ResvgPrivate
/**
* @brief QSvgRenderer-like wrapper for resvg C-API
*/
class ResvgRenderer {
public:
/**
* @brief Constructs a new renderer.
*/
ResvgRenderer();
/**
* @brief Constructs a new renderer and loads the contents of the SVG(Z) file.
*/
ResvgRenderer(const QString &filePath);
/**
* @brief Constructs a new renderer and loads the SVG data.
*/
ResvgRenderer(const QByteArray &data);
/**
* @brief Destructs the renderer.
*/
~ResvgRenderer();
/**
* @brief Loads the contents of the SVG(Z) file.
*/
bool load(const QString &filePath);
/**
* @brief Loads the SVG data.
*/
bool load(const QByteArray &data);
/**
* @brief Returns \b true if the file or data were loaded successful.
*/
bool isValid() const;
/**
* @brief Returns an underling error when #isValid is \b false.
*/
QString errorString() const;
/**
* @brief Checks that underling tree has any nodes.
*
* #ResvgRenderer and #ResvgRenderer constructors
* will set an error only if a file does not exist or it has a non-UTF-8 encoding.
* All other errors will result in an empty tree with a 100x100px size.
*
* @return Returns \b true if tree has any nodes.
*/
bool isEmpty() const;
/**
* @brief Returns an SVG size.
*/
QSize defaultSize() const;
/**
* @brief Returns an SVG size.
*/
QSizeF defaultSizeF() const;
/**
* @brief Returns an SVG viewbox.
*/
QRect viewBox() const;
/**
* @brief Returns an SVG viewbox.
*/
QRectF viewBoxF() const;
/**
* @brief Returns bounding rectangle of the item with the given \b id.
* The transformation matrix of parent elements is not affecting
* the bounds of the element.
*/
QRectF boundsOnElement(const QString &id) const;
/**
* @brief Returns \b true if element with such an ID exists.
*/
bool elementExists(const QString &id) const;
/**
* @brief Returns element's transform.
*/
QTransform transformForElement(const QString &id) const;
/**
* @brief Renders the SVG data to canvas.
*/
void render(QPainter *p);
/**
* @brief Renders the SVG data to canvas with the specified \b bounds.
*
* If the bounding rectangle is not specified
* the SVG file is mapped to the whole paint device.
*/
void render(QPainter *p, const QRectF &bounds);
/**
* @brief Renders the given element with \b elementId on the specified \b bounds.
*
* If the bounding rectangle is not specified
* the SVG element is mapped to the whole paint device.
*/
void render(QPainter *p, const QString &elementId,
const QRectF &bounds = QRectF());
/**
* @brief Initializes the library log.
*
* Use it if you want to see any warnings.
*
* Must be called only once.
*
* All warnings will be printed to the \b stderr.
*/
static void initLog();
private:
QScopedPointer<ResvgPrivate::Data> d;
};
// Implementation.
inline ResvgRenderer::ResvgRenderer()
: d(new ResvgPrivate::Data())
{
}
ResvgRenderer::ResvgRenderer(const QString &filePath)
: d(new ResvgRendererPrivate())
inline ResvgRenderer::ResvgRenderer(const QString &filePath)
: d(new ResvgPrivate::Data())
{
load(filePath);
}
ResvgRenderer::ResvgRenderer(const QByteArray &data)
: d(new ResvgRendererPrivate())
inline ResvgRenderer::ResvgRenderer(const QByteArray &data)
: d(new ResvgPrivate::Data())
{
load(data);
}
ResvgRenderer::~ResvgRenderer() {}
inline ResvgRenderer::~ResvgRenderer() {}
bool ResvgRenderer::load(const QString &filePath)
inline bool ResvgRenderer::load(const QString &filePath)
{
// Check for Qt resource path.
if (filePath.startsWith(QLatin1String(":/"))) {
......@@ -123,7 +275,7 @@ bool ResvgRenderer::load(const QString &filePath)
const auto err = resvg_parse_tree_from_file(rawFilePath, &d->opt, &d->tree);
if (err != RESVG_OK) {
d->errMsg = errorToString(err);
d->errMsg = ResvgPrivate::errorToString(err);
return false;
}
......@@ -133,13 +285,13 @@ bool ResvgRenderer::load(const QString &filePath)
return true;
}
bool ResvgRenderer::load(const QByteArray &data)
inline bool ResvgRenderer::load(const QByteArray &data)
{
d->reset();
const auto err = resvg_parse_tree_from_data(data.constData(), data.size(), &d->opt, &d->tree);
if (err != RESVG_OK) {
d->errMsg = errorToString(err);
d->errMsg = ResvgPrivate::errorToString(err);
return false;
}
......@@ -149,17 +301,17 @@ bool ResvgRenderer::load(const QByteArray &data)
return true;
}
bool ResvgRenderer::isValid() const
inline bool ResvgRenderer::isValid() const
{
return d->tree;
}
QString ResvgRenderer::errorString() const
inline QString ResvgRenderer::errorString() const
{
return d->errMsg;
}
bool ResvgRenderer::isEmpty() const
inline bool ResvgRenderer::isEmpty() const
{
if (d->tree)
return !resvg_is_image_empty(d->tree);
......@@ -167,12 +319,12 @@ bool ResvgRenderer::isEmpty() const
return true;
}
QSize ResvgRenderer::defaultSize() const
inline QSize ResvgRenderer::defaultSize() const
{
return defaultSizeF().toSize();
}
QSizeF ResvgRenderer::defaultSizeF() const
inline QSizeF ResvgRenderer::defaultSizeF() const
{
if (d->tree)
return d->viewBox.size();
......@@ -180,12 +332,12 @@ QSizeF ResvgRenderer::defaultSizeF() const
return QSizeF();
}
QRect ResvgRenderer::viewBox() const
inline QRect ResvgRenderer::viewBox() const
{
return viewBoxF().toRect();
}
QRectF ResvgRenderer::viewBoxF() const
inline QRectF ResvgRenderer::viewBoxF() const
{
if (d->tree)
return d->viewBox;
......@@ -193,51 +345,52 @@ QRectF ResvgRenderer::viewBoxF() const
return QRectF();
}
QRectF ResvgRenderer::boundsOnElement(const QString &id) const
inline QRectF ResvgRenderer::boundsOnElement(const QString &id) const
{
if (d->tree) {
const auto utf8Str = id.toUtf8();
const auto rawId = utf8Str.constData();
resvg_rect bbox;
if (resvg_qt_get_node_bbox(d->tree, &d->opt, rawId, &bbox)) {
return QRectF(bbox.x, bbox.y, bbox.height, bbox.width);
}
if (!d->tree)
return QRectF();
const auto utf8Str = id.toUtf8();
const auto rawId = utf8Str.constData();
resvg_rect bbox;
if (resvg_qt_get_node_bbox(d->tree, &d->opt, rawId, &bbox)) {
return QRectF(bbox.x, bbox.y, bbox.height, bbox.width);
}
return QRectF();
}
bool ResvgRenderer::elementExists(const QString &id) const
inline bool ResvgRenderer::elementExists(const QString &id) const
{
if (d->tree) {
const auto utf8Str = id.toUtf8();
const auto rawId = utf8Str.constData();
return resvg_node_exists(d->tree, rawId);
}
if (!d->tree)
return false;
return false;
const auto utf8Str = id.toUtf8();
const auto rawId = utf8Str.constData();
return resvg_node_exists(d->tree, rawId);
}
QTransform ResvgRenderer::transformForElement(const QString &id) const
inline QTransform ResvgRenderer::transformForElement(const QString &id) const
{
if (d->tree) {
const auto utf8Str = id.toUtf8();
const auto rawId = utf8Str.constData();
resvg_transform ts;
if (resvg_get_node_transform(d->tree, rawId, &ts)) {
return QTransform(ts.a, ts.b, ts.c, ts.d, ts.e, ts.f);
}
if (!d->tree)
return QTransform();
const auto utf8Str = id.toUtf8();
const auto rawId = utf8Str.constData();
resvg_transform ts;
if (resvg_get_node_transform(d->tree, rawId, &ts)) {
return QTransform(ts.a, ts.b, ts.c, ts.d, ts.e, ts.f);
}
return QTransform();
}
void ResvgRenderer::render(QPainter *p)
inline void ResvgRenderer::render(QPainter *p)
{
render(p, QRectF());
}
void ResvgRenderer::render(QPainter *p, const QRectF &bounds)
inline void ResvgRenderer::render(QPainter *p, const QRectF &bounds)
{
if (!d->tree)
return;
......@@ -258,7 +411,7 @@ void ResvgRenderer::render(QPainter *p, const QRectF &bounds)
p->restore();
}
void ResvgRenderer::render(QPainter *p, const QString &elementId, const QRectF &bounds)
inline void ResvgRenderer::render(QPainter *p, const QString &elementId, const QRectF &bounds)
{
if (!d->tree)
return;
......@@ -287,7 +440,11 @@ void ResvgRenderer::render(QPainter *p, const QString &elementId, const QRectF &
p->restore();
}
void ResvgRenderer::initLog()
inline void ResvgRenderer::initLog()
{
resvg_init_log();
}
#undef RESVG_QT_BACKEND
#endif // RESVGQT_H
......@@ -180,18 +180,7 @@ void resvg_init_log();
/**
* @brief Initializes the #resvg_options structure.
*/
void resvg_init_options(resvg_options *opt)
{
opt->path = NULL;
opt->dpi = 96;
opt->fit_to.type = RESVG_FIT_TO_ORIGINAL;
opt->fit_to.value = 0;
opt->draw_background = false;
opt->background.r = 0;
opt->background.g = 0;
opt->background.b = 0;
opt->keep_named_groups = false;
}
void resvg_init_options(resvg_options *opt);
/**
* @brief Creates #resvg_render_tree from file.
......@@ -228,10 +217,6 @@ int resvg_parse_tree_from_data(const char *data,
/**
* @brief Checks that tree has any nodes.
*
* #resvg_parse_tree_from_file and #resvg_parse_tree_from_data methods
* will return an error only if a file does not exist or it has a non-UTF-8 encoding.
* All other errors will result in an empty tree with a 100x100px size.
*
* @param tree Render tree.
* @return Returns \b true if tree has any nodes.
*/
......
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
/**
* @file ResvgQt.h
*
* Qt wrapper for resvg C-API
*/
#ifndef RESVGQT_H
#define RESVGQT_H
#include <QString>
#include <QScopedPointer>
#include <QRectF>
#include <QTransform>
class QPainter;
class ResvgRendererPrivate;
/**
* @brief QSvgRenderer-like wrapper for resvg C-API
*/
class ResvgRenderer {
public:
/**
* @brief Constructs a new renderer.
*/
ResvgRenderer();
/**
* @brief Constructs a new renderer and loads the contents of the SVG(Z) file.
*/
ResvgRenderer(const QString &filePath);
/**
* @brief Constructs a new renderer and loads the SVG data.
*/
ResvgRenderer(const QByteArray &data);
/**
* @brief Destructs the renderer.
*/
~ResvgRenderer();
/**
* @brief Loads the contents of the SVG(Z) file.
*/
bool load(const QString &filePath);
/**
* @brief Loads the SVG data.
*/
bool load(const QByteArray &data);
/**
* @brief Returns \b true if the file or data were loaded successful.
*/
bool isValid() const;
/**
* @brief Returns an underling error when #isValid is \b false.
*/
QString errorString() const;
/**
* @brief Checks that underling tree has any nodes.
*
* #ResvgRenderer and #ResvgRenderer constructors
* will set an error only if a file does not exist or it has a non-UTF-8 encoding.
* All other errors will result in an empty tree with a 100x100px size.
*
* @return Returns \b true if tree has any nodes.
*/
bool isEmpty() const;
/**
* @brief Returns an SVG size.
*/
QSize defaultSize() const;
/**
* @brief Returns an SVG size.
*/
QSizeF defaultSizeF() const;
/**
* @brief Returns an SVG viewbox.
*/
QRect viewBox() const;
/**
* @brief Returns an SVG viewbox.
*/
QRectF viewBoxF() const;
/**
* @brief Returns bounding rectangle of the item with the given \b id.
* The transformation matrix of parent elements is not affecting
* the bounds of the element.
*/
QRectF boundsOnElement(const QString &id) const;
/**
* @brief Returns \b true if element with such an ID exists.
*/
bool elementExists(const QString &id) const;
/**
* @brief Returns element's transform.
*/
QTransform transformForElement(const QString &id) const;
/**
* @brief Renders the SVG data to canvas.
*/
void render(QPainter *p);
/**
* @brief Renders the SVG data to canvas with the specified \b bounds.
*
* If the bounding rectangle is not specified
* the SVG file is mapped to the whole paint device.
*/
void render(QPainter *p, const QRectF &bounds);
/**
* @brief Renders the given element with \b elementId on the specified \b bounds.
*
* If the bounding rectangle is not specified
* the SVG element is mapped to the whole paint device.
*/
void render(QPainter *p, const QString &elementId,
const QRectF &bounds = QRectF());
/**
* @brief Initializes the library log.
*
* Use it if you want to see any warnings.
*
* Must be called only once.
*
* All warnings will be printed to the \b stderr.
*/
static void initLog();
private:
QScopedPointer<ResvgRendererPrivate> d;
};
#endif // RESVGQT_H
......@@ -11,9 +11,7 @@ QMAKE_CXXFLAGS += -Wextra -Wpedantic
QMAKE_CXXFLAGS += -fsanitize=address
QMAKE_LFLAGS += -fsanitize=address
SOURCES += \
tst_resvgqt.cpp \
$$PWD/../qt-wrapper/ResvgQt.cpp
SOURCES += tst_resvgqt.cpp
DEFINES += SRCDIR=\\\"$$PWD\\\"
......@@ -22,5 +20,3 @@ else:CONFIG(debug, debug|release): LIBS += -L$$PWD/../../target/debug/ -lresvg
INCLUDEPATH += $$PWD/../include
DEPENDPATH += $$PWD/../include
INCLUDEPATH += $$PWD/../qt-wrapper
......@@ -18,6 +18,7 @@ use std::path;
use std::ffi::CStr;
use std::os::raw::c_char;
use std::slice;
use std::ptr;
#[cfg(feature = "qt-backend")]
use resvg::qt;
......@@ -143,6 +144,23 @@ fn log_format(out: fern::FormatCallback, message: &fmt::Arguments, record: &log:
))
}
#[no_mangle]
pub extern fn resvg_init_options(opt: *mut resvg_options) {
unsafe {
(*opt).path = ptr::null();
(*opt).dpi = 96.0;
(*opt).fit_to = resvg_fit_to {
kind: resvg_fit_to_type::RESVG_FIT_TO_ORIGINAL,
value: 0.0,
};
(*opt).draw_background = false;
(*opt).background.r = 0;
(*opt).background.g = 0;
(*opt).background.b = 0;
(*opt).keep_named_groups = false;
}
}
#[no_mangle]
pub extern fn resvg_parse_tree_from_file(
file_path: *const c_char,
......
......@@ -7,8 +7,7 @@ CONFIG += C++11
SOURCES += \
main.cpp \
mainwindow.cpp \
svgview.cpp \
../../capi/qt-wrapper/ResvgQt.cpp
svgview.cpp
HEADERS += \
mainwindow.h \
......@@ -25,5 +24,3 @@ else:CONFIG(debug, debug|release): LIBS += -L$$PWD/../../target/debug/ -lresvg
INCLUDEPATH += $$PWD/../../capi/include
DEPENDPATH += $$PWD/../../capi/include
INCLUDEPATH += $$PWD/../../capi/qt-wrapper
......@@ -5,8 +5,7 @@ TEMPLATE = app
SOURCES += \
main.cpp \
svgview.cpp \
mainwindow.cpp \
../../capi/qt-wrapper/ResvgQt.cpp
mainwindow.cpp
HEADERS += \
svgview.h \
......@@ -23,5 +22,3 @@ else:CONFIG(debug, debug|release): LIBS += -L$$PWD/../../target/debug/ -lresvg
INCLUDEPATH += $$PWD/../../capi/include
DEPENDPATH += $$PWD/../../capi/include
INCLUDEPATH += $$PWD/../../capi/qt-wrapper
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment