Skip to content

Commit

Permalink
feat: add basic measureText setup
Browse files Browse the repository at this point in the history
  • Loading branch information
doodlewind authored and Brooooooklyn committed Jul 27, 2021
1 parent 70fd049 commit e1fc0bf
Show file tree
Hide file tree
Showing 6 changed files with 327 additions and 171 deletions.
106 changes: 68 additions & 38 deletions skia-c/skia_c.cpp
Expand Up @@ -293,21 +293,14 @@ extern "C"
int weight,
int width,
int slant,
skiac_typeface_font_provider *c_typeface_font_provider,
skiac_font_mgr *c_font_mgr,
skiac_font_collection *font_collection,
float font_size,
const char *font_family,
float baseline_offset,
uint8_t align,
float align_factor,
skiac_paint *c_paint)
{
auto font_collection = sk_make_sp<FontCollection>();
auto font_provider = sp_from_const(reinterpret_cast<TypefaceFontProvider *>(c_typeface_font_provider));
auto default_font_mgr = sp_from_const(reinterpret_cast<SkFontMgr *>(c_font_mgr));
font_collection->setDefaultFontManager(default_font_mgr);
font_collection->setAssetFontManager(font_provider);
font_collection->enableFontFallback();
TextStyle text_style;
auto font_style = SkFontStyle(weight, width, (SkFontStyle::Slant)slant);
const std::vector<SkString> families = {SkString(font_family)};
Expand All @@ -322,7 +315,7 @@ extern "C"
paragraph_style.turnHintingOff();
paragraph_style.setTextStyle(text_style);
paragraph_style.setTextAlign((TextAlign)align);
auto builder = ParagraphBuilderImpl::make(paragraph_style, font_collection).release();
auto builder = ParagraphBuilderImpl::make(paragraph_style, font_collection->collection).release();
builder->pushStyle(text_style);
builder->addText(text, text_len);

Expand All @@ -341,6 +334,7 @@ extern "C"
CANVAS_CAST->save();
CANVAS_CAST->scale(max_width / line_width, 1.0);
}

auto paint_y = y + baseline_offset - paragraph->getHeight() - alphabetic_baseline;
paragraph->paint(CANVAS_CAST, paint_x, paint_y);
if (need_scale)
Expand All @@ -350,6 +344,52 @@ extern "C"
delete paragraph;
}

skiac_line_metrics skiac_canvas_get_line_metrics(
const char *text,
skiac_font_collection *c_collection,
float font_size,
const char *font_family,
uint8_t align,
float align_factor,
skiac_paint *c_paint)
{
auto font_collection = c_collection->collection;

TextStyle text_style;
text_style.setFontFamilies({SkString(font_family)});
text_style.setFontSize(font_size);
text_style.setWordSpacing(0);
text_style.setHeight(1);

ParagraphStyle paragraph_style;
paragraph_style.turnHintingOff();
paragraph_style.setTextStyle(text_style);
paragraph_style.setTextAlign((TextAlign)align);

auto builder = ParagraphBuilder::make(paragraph_style, font_collection);
builder->addText(text, strlen(text));

auto paragraph = builder->Build();
paragraph->layout(MAX_LAYOUT_WIDTH);

auto metrics_vec = std::vector<LineMetrics>();
paragraph->getLineMetrics(metrics_vec);
auto line_metrics = metrics_vec[0];
SkDebugf("ascent %f\ndescent %f\nleft %f\nwidth %f\nbaseline %f\n",
line_metrics.fAscent,
line_metrics.fDescent,
line_metrics.fLeft,
line_metrics.fWidth,
line_metrics.fBaseline);
skiac_line_metrics result;
result.ascent = line_metrics.fAscent;
result.descent = line_metrics.fDescent;
result.left = line_metrics.fLeft;
result.width = line_metrics.fWidth;
result.baseline = line_metrics.fBaseline;
return result;
}

void skiac_canvas_reset_transform(skiac_canvas *c_canvas)
{
CANVAS_CAST->resetMatrix();
Expand Down Expand Up @@ -1106,55 +1146,45 @@ extern "C"
delete FONT_METRICS_CAST;
}

skiac_font_mgr *skiac_font_mgr_ref_default()
skiac_font_collection *skiac_font_collection_create()
{
return reinterpret_cast<skiac_font_mgr *>(SkFontMgr_New_Custom_Empty().release());
return new skiac_font_collection();
}

uint32_t skiac_font_mgr_get_default_fonts_count(skiac_font_mgr *c_font_mgr)
skiac_font_collection *skiac_font_collection_clone(skiac_font_collection *c_font_collection)
{
return reinterpret_cast<SkFontMgr *>(c_font_mgr)->countFamilies();
return new skiac_font_collection(c_font_collection->collection);
}

void skiac_font_mgr_get_family(skiac_font_mgr *c_font_mgr, uint32_t i, skiac_string *c_string)
uint32_t skiac_font_collection_get_default_fonts_count(skiac_font_collection *c_font_collection)
{
return c_font_collection->font_mgr->countFamilies();
}

void skiac_font_collection_get_family(skiac_font_collection *c_font_collection, uint32_t i, skiac_string *c_string)
{
auto name = new SkString();
reinterpret_cast<SkFontMgr *>(c_font_mgr)->getFamilyName(i, name);
c_font_collection->font_mgr->getFamilyName(i, name);
c_string->length = name->size();
c_string->ptr = name->c_str();
c_string->sk_string = name;
}

skiac_typeface_font_provider *skiac_typeface_font_provider_create()
{
auto fp = new TypefaceFontProvider();
return reinterpret_cast<skiac_typeface_font_provider *>(fp);
}

size_t skiac_typeface_font_provider_register(skiac_typeface_font_provider *c_typeface_font_provider, skiac_font_mgr *c_font_mgr, uint8_t *font, size_t length)
size_t skiac_font_collection_register(skiac_font_collection *c_font_collection, const uint8_t *font, size_t length)
{
auto fp = reinterpret_cast<TypefaceFontProvider *>(c_typeface_font_provider);
auto font_mgr = reinterpret_cast<SkFontMgr *>(c_font_mgr);
auto typeface_data = SkData::MakeWithCopy(font, length);
auto typeface = font_mgr->makeFromData(typeface_data);
return fp->registerTypeface(typeface);
}

size_t skiac_typeface_font_provider_register_from_file(skiac_typeface_font_provider *c_typeface_font_provider, skiac_font_mgr *c_font_mgr, const char *font_path)
{
auto fp = reinterpret_cast<TypefaceFontProvider *>(c_typeface_font_provider);
auto font_mgr = reinterpret_cast<SkFontMgr *>(c_font_mgr);
auto typeface = font_mgr->makeFromFile(font_path);
return fp->registerTypeface(typeface);
auto typeface = c_font_collection->font_mgr->makeFromData(typeface_data);
return c_font_collection->assets->registerTypeface(typeface);
}

void skiac_typeface_font_provider_ref(skiac_typeface_font_provider *c_typeface_font_provider)
size_t skiac_font_collection_register_from_path(skiac_font_collection *c_font_collection, const char *font_path)
{
reinterpret_cast<TypefaceFontProvider *>(c_typeface_font_provider)->ref();
auto typeface = c_font_collection->font_mgr->makeFromFile(font_path);
return c_font_collection->assets->registerTypeface(typeface);
}

void skiac_typeface_font_provider_unref(skiac_typeface_font_provider *c_typeface_font_provider)
void skiac_font_collection_destroy(skiac_font_collection *c_font_collection)
{
reinterpret_cast<TypefaceFontProvider *>(c_typeface_font_provider)->unref();
delete c_font_collection;
}
}
57 changes: 51 additions & 6 deletions skia-c/skia_c.hpp
Expand Up @@ -62,6 +62,40 @@ typedef struct skiac_font_collection skiac_font_collection;

sk_sp<SkFontMgr> SkFontMgr_New_Custom_Empty();

struct skiac_font_collection
{
sk_sp<FontCollection> collection;
sk_sp<SkFontMgr> font_mgr;
sk_sp<TypefaceFontProvider> assets;
skiac_font_collection()
{
font_mgr = SkFontMgr_New_Custom_Empty();
assets = sk_make_sp<TypefaceFontProvider>();
collection = sk_make_sp<FontCollection>();
collection->setDefaultFontManager(font_mgr);
collection->setAssetFontManager(assets);
collection->enableFontFallback();
}
skiac_font_collection(sk_sp<FontCollection> collection)
{
font_mgr = SkFontMgr_New_Custom_Empty();
assets = sk_make_sp<TypefaceFontProvider>();
collection->setDefaultFontManager(font_mgr);
collection->enableFontFallback();
collection->setAssetFontManager(assets);
this->collection = collection;
}
};

struct skiac_line_metrics
{
float ascent;
float descent;
float left;
float width;
float baseline;
};

struct skiac_rect
{
float left;
Expand Down Expand Up @@ -168,14 +202,21 @@ extern "C"
int weight,
int width,
int slant,
skiac_typeface_font_provider *c_typeface_font_provider,
skiac_font_mgr *c_font_mgr,
skiac_font_collection *font_collection,
float font_size,
const char *font_family,
float baseline_offset,
uint8_t align,
float align_factor,
skiac_paint *c_paint);
skiac_line_metrics skiac_canvas_get_line_metrics(
const char *text,
skiac_font_collection *c_collection,
float font_size,
const char *font_family,
uint8_t align,
float align_factor,
skiac_paint *c_paint);
void skiac_canvas_reset_transform(skiac_canvas *c_canvas);
void skiac_canvas_clip_rect(skiac_canvas *c_canvas, float x, float y, float w, float h);
void skiac_canvas_clip_path(skiac_canvas *c_canvas, skiac_path *c_path);
Expand Down Expand Up @@ -333,10 +374,14 @@ extern "C"
skiac_font_metrics *skiac_font_metrics_create(const char *font_family, float font_size);
void skiac_font_metrics_destroy(skiac_font_metrics *c_font_metrics);

// FontMgr
skiac_font_mgr *skiac_font_mgr_ref_default();
uint32_t skiac_font_mgr_get_default_fonts_count(skiac_font_mgr *c_font_mgr);
void skiac_font_mgr_get_family(skiac_font_mgr *c_font_mgr, uint32_t i, skiac_string *c_string);
// FontCollection
skiac_font_collection *skiac_font_collection_create();
skiac_font_collection *skiac_font_collection_clone(skiac_font_collection *c_font_collection);
uint32_t skiac_font_collection_get_default_fonts_count(skiac_font_collection *c_font_collection);
void skiac_font_collection_get_family(skiac_font_collection *c_font_collection, uint32_t i, skiac_string *c_string);
size_t skiac_font_collection_register(skiac_font_collection *c_font_collection, const uint8_t *font, size_t length);
size_t skiac_font_collection_register_from_path(skiac_font_collection *c_font_collection, const char *font_path);
void skiac_font_collection_destroy(skiac_font_collection *c_font_collection);
}

#endif // SKIA_CAPI_H
65 changes: 55 additions & 10 deletions src/ctx.rs
@@ -1,6 +1,7 @@
use std::convert::TryInto;
use std::f32::consts::PI;
use std::mem;
use std::rc::Rc;
use std::result;
use std::str::FromStr;

Expand Down Expand Up @@ -28,7 +29,7 @@ pub struct Context {
path: Path,
pub alpha: bool,
pub(crate) states: Vec<Context2dRenderingState>,
pub typeface_font_provider: TypefaceFontProvider,
pub font_collection: Rc<FontCollection>,
}

impl Context {
Expand Down Expand Up @@ -111,6 +112,7 @@ impl Context {
Property::new(env, "isPointInStroke")?.with_method(is_point_in_stroke),
Property::new(env, "ellipse")?.with_method(ellipse),
Property::new(env, "lineTo")?.with_method(line_to),
Property::new(env, "measureText")?.with_method(measure_text),
Property::new(env, "moveTo")?.with_method(move_to),
Property::new(env, "fill")?.with_method(fill),
Property::new(env, "fillRect")?.with_method(fill_rect),
Expand Down Expand Up @@ -139,11 +141,7 @@ impl Context {
}

#[inline(always)]
pub fn new(
width: u32,
height: u32,
typeface_font_provider: &mut TypefaceFontProvider,
) -> Result<Self> {
pub fn new(width: u32, height: u32, font_collection: &mut Rc<FontCollection>) -> Result<Self> {
let surface = Surface::new_rgba(width, height)
.ok_or_else(|| Error::from_reason("Create skia surface failed".to_owned()))?;
let states = vec![Context2dRenderingState::default()];
Expand All @@ -152,7 +150,7 @@ impl Context {
alpha: true,
path: Path::new(),
states,
typeface_font_provider: typeface_font_provider.clone(),
font_collection: font_collection.clone(),
})
}

Expand Down Expand Up @@ -499,7 +497,7 @@ impl Context {
weight,
stretch as u32,
slant,
&self.typeface_font_provider,
&self.font_collection,
state.font_style.size,
&state.font_style.family,
state.text_baseline,
Expand All @@ -517,7 +515,7 @@ impl Context {
weight,
stretch as u32,
slant,
&self.typeface_font_provider,
&self.font_collection,
state.font_style.size,
&state.font_style.family,
state.text_baseline,
Expand All @@ -527,6 +525,22 @@ impl Context {
Ok(())
}

#[inline(always)]
fn get_line_metrics(&mut self, text: &str) -> result::Result<LineMetrics, SkError> {
let state = self.states.last().unwrap();
let fill_paint = self.fill_paint()?;

let line_metrics = LineMetrics(self.surface.canvas.get_line_metrics(
text,
&self.font_collection,
state.font_style.size,
&state.font_style.family,
state.text_align,
&fill_paint,
));
Ok(line_metrics)
}

#[inline(always)]
fn apply_shadow_offset_matrix(
surface: &mut Surface,
Expand All @@ -553,7 +567,7 @@ fn context_2d_constructor(ctx: CallContext) -> Result<JsUndefined> {
let typeface_font_provider_js = ctx.get::<JsObject>(2)?;
let typeface_font_provider = ctx
.env
.unwrap::<TypefaceFontProvider>(&typeface_font_provider_js)?;
.unwrap::<Rc<FontCollection>>(&typeface_font_provider_js)?;

let mut this = ctx.this_unchecked::<JsObject>();
let context_2d = Context::new(width, height, typeface_font_provider)?;
Expand Down Expand Up @@ -1024,6 +1038,37 @@ fn line_to(ctx: CallContext) -> Result<JsUndefined> {
ctx.env.get_undefined()
}

#[js_function(1)]
fn measure_text(ctx: CallContext) -> Result<JsObject> {
let text = ctx.get::<JsString>(0)?.into_utf8()?;
let this = ctx.this_unchecked::<JsObject>();
let context_2d = ctx.env.unwrap::<Context>(&this)?;

let m = context_2d.get_line_metrics(text.as_str()?)?.0;

let mut metrics = ctx.env.create_object()?;
metrics.set_named_property(
"actualBoundingBoxAscent",
ctx.env.create_double(m.descent as f64)?,
)?;
metrics.set_named_property(
"actualBoundingBoxDescent",
ctx.env.create_double(m.ascent as f64)?,
)?;
metrics.set_named_property(
"actualBoundingBoxLeft",
ctx.env.create_double(m.left as f64)?,
)?;
metrics.set_named_property(
"actualBoundingBoxRight",
ctx.env.create_double((m.left + m.width) as f64)?,
)?;
// metrics.set_named_property("fontBoundingBoxAscent", ctx.env.create_double(m.ascent)?)?;
// metrics.set_named_property("fontBoundingBoxDescent", ctx.env.create_double(mn.descent)?)?;
metrics.set_named_property("width", ctx.env.create_double(m.width as f64)?)?;
Ok(metrics)
}

#[js_function(2)]
fn move_to(ctx: CallContext) -> Result<JsUndefined> {
let this = ctx.this_unchecked::<JsObject>();
Expand Down

0 comments on commit e1fc0bf

Please sign in to comment.