Commit d7c1a3d8 authored by RazrFalcon's avatar RazrFalcon

Added 'systemLanguage' attribute support.

parent 28d0d3dc
......@@ -9,8 +9,10 @@ This changelog also contains an important changes in dependencies.
## [Unreleased]
### Added
- (c-api) `RESVG_ERROR_PARSING_FAILED`.
- (c-api) `resvg_options::font_family` and `resvg_options::font_size`.
- (c-api) `font_family`, `font_size` and `languages` to `resvg_options`.
- (usvg) Default font family and size is configurable now.
- (usvg) `systemLanguage` attribute support.
- (rendersvg) `font-family`, `font-size` and `languages` to args.
### Changed
- (rendersvg) Use `gumdrop` instead of `getopts`.
......
......@@ -30,7 +30,7 @@ travis-ci = { repository = "RazrFalcon/resvg" }
[dependencies]
log = "0.4.5"
#usvg = "0.2"
usvg = { git = "https://github.com/RazrFalcon/usvg", rev = "405ad77" }
usvg = { git = "https://github.com/RazrFalcon/usvg", rev = "5678e1a" }
#usvg = { path = "../usvg" }
# cairo backend
cairo-rs = { version = "0.5", features = ["png"], optional = true }
......
......@@ -31,15 +31,11 @@ extern "C" {
namespace ResvgPrivate {
static void initOptions(resvg_options &opt)
static const char* toCStr(const QString &text)
{
resvg_init_options(&opt);
const auto screens = qApp->screens();
if (!screens.isEmpty()) {
const auto screen = screens.at(0);
opt.dpi = screen->logicalDotsPerInch() * screen->devicePixelRatio();
}
const auto utf8 = text.toUtf8();
const auto data = utf8.constData();
return qstrdup(data);
}
class Data
......@@ -47,15 +43,44 @@ class Data
public:
Data()
{
resvg_init_options(&opt);
init();
}
~Data()
{
reset();
clear();
}
void reset()
{
clear();
init();
}
resvg_render_tree *tree = nullptr;
resvg_options opt;
QRectF viewBox;
QString errMsg;
private:
void init()
{
resvg_init_options(&opt);
QFont font;
opt.font_family = toCStr(font.family());
opt.font_size = font.pointSize();
opt.languages = toCStr(QLocale().bcp47Name());
const auto screens = qApp->screens();
if (!screens.isEmpty()) {
const auto screen = screens.at(0);
opt.dpi = screen->logicalDotsPerInch() * screen->devicePixelRatio();
}
}
void clear()
{
if (tree) {
resvg_tree_destroy(tree);
......@@ -67,15 +92,19 @@ public:
opt.path = NULL;
}
initOptions(opt);
if (opt.font_family) {
delete[] opt.font_family; // do not use free() because was allocated via qstrdup()
opt.font_family = NULL;
}
if (opt.languages) {
delete[] opt.languages; // do not use free() because was allocated via qstrdup()
opt.languages = NULL;
}
viewBox = QRectF();
errMsg = QString();
}
resvg_render_tree *tree = nullptr;
resvg_options opt;
QRectF viewBox;
QString errMsg;
};
static QString errorToString(const int err)
......@@ -269,11 +298,9 @@ inline bool ResvgRenderer::load(const QString &filePath)
d->reset();
const auto utf8Str = filePath.toUtf8();
const auto rawFilePath = utf8Str.constData();
d->opt.path = qstrdup(rawFilePath);
d->opt.path = ResvgPrivate::toCStr(filePath);
const auto err = resvg_parse_tree_from_file(rawFilePath, &d->opt, &d->tree);
const auto err = resvg_parse_tree_from_file(d->opt.path, &d->opt, &d->tree);
if (err != RESVG_OK) {
d->errMsg = ResvgPrivate::errorToString(err);
return false;
......
......@@ -99,27 +99,60 @@ typedef struct resvg_fit_to {
* @brief Rendering options.
*/
typedef struct resvg_options {
/** SVG image path. Used to resolve relative image paths. */
/** SVG image path. Used to resolve relative image paths.
*
* Default: NULL
*/
const char *path;
/** Output DPI. Default: 96. */
/** Output DPI.
*
* Default: 96.
*/
double dpi;
/** Default font family. Default: 'Timer New Roman'. */
/** Default font family.
*
* Default: NULL.
*/
const char *font_family;
/** Default font size. Default: 12. */
/** Default font size.
*
* Default: 12.
*/
double font_size;
/**
* Sets a comma-separated list of languages that will be used
* during the 'systemLanguage' attribute resolving.
* Examples: 'en-US', 'en-US, ru-RU', 'en, ru'
*
* Default: NULL.
*/
const char *languages;
/**
* Fits the image using specified options.
*
* Default: \b RESVG_FIT_TO_ORIGINAL.
*/
resvg_fit_to fit_to;
/** Draw background. Default: false. */
/** Draw background.
*
* Default: false.
*/
bool draw_background;
/** Background color. */
resvg_color background;
/**
* Keep named groups. If set to \b true, all non-empty
* groups with \b id attribute will not be removed.
*
* Default: false
*/
bool keep_named_groups;
} resvg_options;
......
......@@ -38,6 +38,7 @@ pub struct resvg_options {
pub dpi: f64,
pub font_family: *const c_char,
pub font_size: f64,
pub languages: *const c_char,
pub fit_to: resvg_fit_to,
pub draw_background: bool,
pub background: resvg_color,
......@@ -153,8 +154,9 @@ pub extern fn resvg_init_options(opt: *mut resvg_options) {
unsafe {
(*opt).path = ptr::null();
(*opt).dpi = 96.0;
(*opt).font_family = b"Times New Roman\0".as_ptr() as *const _;
(*opt).font_family = ptr::null();
(*opt).font_size = 12.0;
(*opt).languages = ptr::null();
(*opt).fit_to = resvg_fit_to {
kind: resvg_fit_to_type::RESVG_FIT_TO_ORIGINAL,
value: 0.0,
......@@ -666,24 +668,45 @@ fn to_native_opt(opt: &resvg_options) -> resvg::Options {
let font_family = match cstr_to_str(opt.font_family) {
Some(v) => {
if v.is_empty() {
warn!("Provided 'font_family' is empty. Fallback to '{}'.", ff);
warn!("Provided 'font_family' option is empty. Fallback to '{}'.", ff);
ff
} else {
v
}
}
None => {
warn!("Provided 'font_family' is no an UTF-8 string. Fallback to '{}'.", ff);
warn!("Provided 'font_family' option is no an UTF-8 string. Fallback to '{}'.", ff);
ff
}
};
let languages_str = match cstr_to_str(opt.languages) {
Some(v) => v,
None => {
warn!("Provided 'languages' option is no an UTF-8 string. Fallback to 'en'.");
"en"
}
};
let mut languages = Vec::new();
for lang in languages_str.split(',') {
languages.push(lang.trim().to_string());
}
if languages.is_empty() {
warn!("Provided 'languages' option is empty. Fallback to 'en'.");
languages = vec!["en".to_string()]
}
resvg::Options {
usvg: usvg::Options {
path,
dpi: opt.dpi,
font_family: font_family.to_string(),
font_size: opt.font_size,
languages,
keep_named_groups: opt.keep_named_groups,
},
fit_to,
......
......@@ -26,6 +26,7 @@ pub fn load_sub_svg(
dpi: opt.usvg.dpi,
font_family: opt.usvg.font_family.clone(),
font_size: opt.usvg.font_size,
languages: opt.usvg.languages.clone(),
keep_named_groups: false,
},
fit_to: FitTo::Original,
......
a-systemLanguage-004.svg
a-systemLanguage-009.svg
a-systemLanguage-010.svg
e-switch-002.svg
e-switch-008.svg
a-systemLanguage-004.svg
a-systemLanguage-009.svg
a-systemLanguage-010.svg
e-switch-002.svg
e-switch-008.svg
......@@ -30,25 +30,34 @@ OPTIONS:
--help Prints help information
-V, --version Prints version information
--perf Prints performance stats
--pretend Does all the steps except rendering
--quiet Disables warnings
--dump-svg=<PATH> Saves the preprocessed SVG to the selected file
--query-all Queries all valid SVG ids with bounding boxes
--export-id=<ID> Renders an object only with a specified ID
--backend=<BACKEND> Sets the rendering backend.
--backend BACKEND Sets the rendering backend.
Has no effect if built with only one backend
[default: {}] [possible values: {}]
--background=<COLOR> Sets the background color.
Examples: red, #fff, #fff000
--dpi=<DPI> Sets the resolution
-w, --width LENGTH Sets the width in pixels
-h, --height LENGTH Sets the height in pixels
-z, --zoom FACTOR Zooms the image by a factor
--dpi DPI Sets the resolution
[default: 96] [possible values: 10..4000]
-w, --width=<LENGTH> Sets the width in pixels
-h, --height=<LENGTH> Sets the height in pixels
-z, --zoom=<FACTOR> Zooms the image by a factor
--background COLOR Sets the background color.
Examples: red, #fff, #fff000
--font-family FAMILY Sets the default font family
[default: 'Times New Roman']
--font-size SIZE Sets the default font size
[default: 12] [possible values: 1..192]
--languages LANG Sets a comma-separated list of languages that will be used
during the 'systemLanguage' attribute resolving.
Examples: 'en-US', 'en-US, ru-RU', 'en, ru'
[default: 'en']
--query-all Queries all valid SVG ids with bounding boxes
--export-id ID Renders an object only with a specified ID
--perf Prints performance stats
--pretend Does all the steps except rendering
--quiet Disables warnings
--dump-svg=<PATH> Saves the preprocessed SVG to the selected file
ARGS:
<in-svg> Input file
......@@ -65,17 +74,32 @@ struct CliArgs {
#[options(short = "V")]
version: bool,
#[options(no_short)]
perf: bool,
#[options(no_short, meta = "BACKEND")]
backend: Option<String>,
#[options(no_short)]
pretend: bool,
#[options(short = "w", meta = "LENGTH", parse(try_from_str = "parse_length"))]
width: Option<u32>,
#[options(no_short)]
quiet: bool,
#[options(short = "h", meta = "LENGTH", parse(try_from_str = "parse_length"))]
height: Option<u32>,
#[options(no_short, meta = "PATH")]
dump_svg: Option<String>,
#[options(short = "z", meta = "ZOOM", parse(try_from_str = "parse_zoom"))]
zoom: Option<f32>,
#[options(no_short, meta = "DPI", default = "96", parse(try_from_str = "parse_dpi"))]
dpi: u32,
#[options(no_short, meta = "COLOR", parse(try_from_str = "parse_color"))]
background: Option<usvg::Color>,
#[options(no_short, meta = "FAMILY", default = "Times New Roman")]
font_family: String,
#[options(no_short, meta = "SIZE", default = "12", parse(try_from_str = "parse_font_size"))]
font_size: u32,
#[options(no_short, meta = "LANG", parse(try_from_str = "parse_languages"))]
languages: Option<Vec<String>>,
#[options(no_short)]
query_all: bool,
......@@ -83,23 +107,17 @@ struct CliArgs {
#[options(no_short, meta = "ID")]
export_id: Option<String>,
#[options(no_short, meta = "BACKEND")]
backend: Option<String>,
#[options(no_short, meta = "COLOR", parse(try_from_str = "parse_color"))]
background: Option<usvg::Color>,
#[options(no_short, meta = "DPI", default = "96", parse(try_from_str = "parse_dpi"))]
dpi: u32,
#[options(no_short)]
perf: bool,
#[options(short = "w", meta = "LENGTH", parse(try_from_str = "parse_length"))]
width: Option<u32>,
#[options(no_short)]
pretend: bool,
#[options(short = "h", meta = "LENGTH", parse(try_from_str = "parse_length"))]
height: Option<u32>,
#[options(no_short)]
quiet: bool,
#[options(short = "z", meta = "ZOOM", parse(try_from_str = "parse_zoom"))]
zoom: Option<f32>,
#[options(no_short, meta = "PATH")]
dump_svg: Option<String>,
#[options(free)]
free: Vec<String>,
......@@ -139,6 +157,29 @@ fn parse_zoom(s: &str) -> Result<f32, &'static str> {
}
}
fn parse_font_size(s: &str) -> Result<u32, &'static str> {
let n: u32 = s.parse().map_err(|_| "invalid number")?;
if n > 0 && n <= 192 {
Ok(n)
} else {
Err("font size out of bounds")
}
}
fn parse_languages(s: &str) -> Result<Vec<String>, &'static str> {
let mut langs = Vec::new();
for lang in s.split(',') {
langs.push(lang.trim().to_string());
}
if langs.is_empty() {
return Err("languages list cannot be empty");
}
Ok(langs)
}
pub struct Args {
pub in_svg: path::PathBuf,
pub out_png: Option<path::PathBuf>,
......@@ -211,12 +252,18 @@ pub fn parse() -> Result<(Args, Options), String> {
fit_to = FitTo::Zoom(z);
}
let languages = match args.languages.as_ref() {
Some(v) => v.clone(),
None => vec!["en".to_string()], // TODO: use system language
};
let opt = Options {
usvg: usvg::Options {
path: Some(in_svg.into()),
dpi: args.dpi as f64,
font_family: "Times New Roman".to_string(),
font_size: 12.0,
font_family: args.font_family.clone(),
font_size: args.font_size as f64,
languages,
keep_named_groups,
},
fit_to,
......
......@@ -2,6 +2,7 @@
// 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/.
#[allow(unused_imports)] // for Rust >= 1.30
#[macro_use] extern crate gumdrop;
extern crate fern;
extern crate log;
......
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