From 1b6ab4417e0edef3b91d150e6650205f49f04d17 Mon Sep 17 00:00:00 2001 From: reed Date: Mon, 3 Nov 2014 19:55:41 -0800 Subject: add textblobs to lua BUG=skia: TBR= Review URL: https://codereview.chromium.org/688363003 --- include/utils/SkTextBox.h | 10 +++++++ resources/slides.lua | 26 ++++++++++++++--- src/utils/SkLua.cpp | 52 +++++++++++++++++++++++++++++++++- src/utils/SkTextBox.cpp | 72 ++++++++++++++++++++++++++++++++++++++--------- 4 files changed, 141 insertions(+), 19 deletions(-) diff --git a/include/utils/SkTextBox.h b/include/utils/SkTextBox.h index e217076fed..d4372d1b6a 100644 --- a/include/utils/SkTextBox.h +++ b/include/utils/SkTextBox.h @@ -60,6 +60,14 @@ public: int countLines() const; SkScalar getTextHeight() const; + SkTextBlob* snapshotTextBlob(SkScalar* computedBottom) const; + + class Visitor { + public: + virtual ~Visitor() {} + virtual void operator()(const char*, size_t, SkScalar x, SkScalar y, const SkPaint&) = 0; + }; + private: SkRect fBox; SkScalar fSpacingMul, fSpacingAdd; @@ -67,6 +75,8 @@ private: const char* fText; size_t fLen; const SkPaint* fPaint; + + SkScalar visit(Visitor&, const char text[], size_t len, const SkPaint&) const; }; class SkTextLineBreaker { diff --git a/resources/slides.lua b/resources/slides.lua index e96182c2bd..f706a29659 100644 --- a/resources/slides.lua +++ b/resources/slides.lua @@ -1,3 +1,4 @@ +gShowBounds = false gPath = "/skia/trunk/resources/" @@ -37,6 +38,13 @@ function draw_bullet(canvas, x, y, paint, indent) canvas:drawCircle(cx, cy, radius, paint) end +function stroke_rect(canvas, rect, color) + local paint = Sk.newPaint() + paint:setStroke(true); + paint:setColor(color) + canvas:drawRect(rect, paint) +end + function drawSlide(canvas, slide, master_template) template = master_template.slide -- need to sniff the slide to know if we're title or slide @@ -65,10 +73,18 @@ function drawSlide(canvas, slide, master_template) local fm = paint:getFontMetrics() local x_offset = -fm.ascent * node.indent * 1.25 - y = y - fm.ascent * scale - draw_bullet(canvas, x + x_offset, y, paint, node.indent) - canvas:drawText(node.text, x + x_offset, y, paint) - y = y + fm.descent * scale + extra_dy + local bounds = make_rect(x + x_offset, y, 620, 640) + local blob, newBottom = Sk.newTextBlob(node.text, bounds, paint) + draw_bullet(canvas, x + x_offset, y - fm.ascent, paint, node.indent) + canvas:drawTextBlob(blob, 0, 0, paint) + y = newBottom + paint:getTextSize() * .5 + + if gShowBounds then + bounds.bottom = newBottom + stroke_rect(canvas, bounds, {a=1,r=0,g=1,b=0}) + stroke_rect(canvas, blob:bounds(), {a=1,r=1,g=0,b=0}) + end + end end @@ -305,6 +321,8 @@ local keyProcs = { s = spawn_scale_animation, ["="] = function () scale_text_delta(gTemplate, 1) end, ["-"] = function () scale_text_delta(gTemplate, -1) end, + + b = function () gShowBounds = not gShowBounds end, } function onCharHandler(uni) diff --git a/src/utils/SkLua.cpp b/src/utils/SkLua.cpp index 4fdb71404d..12e2dd8ddf 100644 --- a/src/utils/SkLua.cpp +++ b/src/utils/SkLua.cpp @@ -556,6 +556,15 @@ static int lcanvas_drawText(lua_State* L) { return 0; } +static int lcanvas_drawTextBlob(lua_State* L) { + const SkTextBlob* blob = get_ref(L, 2); + SkScalar x = lua2scalar(L, 3); + SkScalar y = lua2scalar(L, 4); + const SkPaint& paint = *get_obj(L, 5); + get_ref(L, 1)->drawTextBlob(blob, x, y, paint); + return 0; +} + static int lcanvas_getSaveCount(lua_State* L) { lua_pushnumber(L, get_ref(L, 1)->getSaveCount()); return 1; @@ -681,6 +690,7 @@ const struct luaL_Reg gSkCanvas_Methods[] = { { "drawPath", lcanvas_drawPath }, { "drawPicture", lcanvas_drawPicture }, { "drawText", lcanvas_drawText }, + { "drawTextBlob", lcanvas_drawTextBlob }, { "getSaveCount", lcanvas_getSaveCount }, { "getTotalMatrix", lcanvas_getTotalMatrix }, { "getClipStack", lcanvas_getClipStack }, @@ -1697,6 +1707,24 @@ static const struct luaL_Reg gSkPicture_Methods[] = { /////////////////////////////////////////////////////////////////////////////// +static int ltextblob_bounds(lua_State* L) { + SkLua(L).pushRect(get_ref(L, 1)->bounds()); + return 1; +} + +static int ltextblob_gc(lua_State* L) { + SkSafeUnref(get_ref(L, 1)); + return 0; +} + +static const struct luaL_Reg gSkTextBlob_Methods[] = { + { "bounds", ltextblob_bounds }, + { "__gc", ltextblob_gc }, + { NULL, NULL } +}; + +/////////////////////////////////////////////////////////////////////////////// + static int ltypeface_gc(lua_State* L) { SkSafeUnref(get_ref(L, 1)); return 0; @@ -1809,6 +1837,26 @@ static int lsk_newRRect(lua_State* L) { return 1; } +#include "SkTextBox.h" +// Sk.newTextBlob(text, rect, paint) +static int lsk_newTextBlob(lua_State* L) { + const char* text = lua_tolstring(L, 1, NULL); + SkRect bounds; + lua2rect(L, 2, &bounds); + const SkPaint& paint = *get_obj(L, 3); + + SkTextBox box; + box.setMode(SkTextBox::kLineBreak_Mode); + box.setBox(bounds); + box.setText(text, strlen(text), paint); + + SkScalar newBottom; + SkAutoTUnref blob(box.snapshotTextBlob(&newBottom)); + push_ref(L, blob); + SkLua(L).pushScalar(newBottom); + return 2; +} + static int lsk_newTypeface(lua_State* L) { const char* name = NULL; int style = SkTypeface::kNormal; @@ -1877,6 +1925,7 @@ static void register_Sk(lua_State* L) { setfield_function(L, "newPictureRecorder", lsk_newPictureRecorder); setfield_function(L, "newRRect", lsk_newRRect); setfield_function(L, "newRasterSurface", lsk_newRasterSurface); + setfield_function(L, "newTextBlob", lsk_newTextBlob); setfield_function(L, "newTypeface", lsk_newTypeface); lua_pop(L, 1); // pop off the Sk table } @@ -1896,6 +1945,7 @@ void SkLua::Load(lua_State* L) { REG_CLASS(L, SkDocument); REG_CLASS(L, SkImage); REG_CLASS(L, SkImageFilter); + REG_CLASS(L, SkMatrix); REG_CLASS(L, SkPaint); REG_CLASS(L, SkPath); REG_CLASS(L, SkPathEffect); @@ -1904,8 +1954,8 @@ void SkLua::Load(lua_State* L) { REG_CLASS(L, SkRRect); REG_CLASS(L, SkShader); REG_CLASS(L, SkSurface); + REG_CLASS(L, SkTextBlob); REG_CLASS(L, SkTypeface); - REG_CLASS(L, SkMatrix); } extern "C" int luaopen_skia(lua_State* L); diff --git a/src/utils/SkTextBox.cpp b/src/utils/SkTextBox.cpp index 55d75a64da..0bb7a6bf5a 100644 --- a/src/utils/SkTextBox.cpp +++ b/src/utils/SkTextBox.cpp @@ -165,14 +165,13 @@ void SkTextBox::setSpacing(SkScalar mul, SkScalar add) ///////////////////////////////////////////////////////////////////////////////////////////// -void SkTextBox::draw(SkCanvas* canvas, const char text[], size_t len, const SkPaint& paint) -{ - SkASSERT(canvas && (text || len == 0)); - +SkScalar SkTextBox::visit(Visitor& visitor, const char text[], size_t len, + const SkPaint& paint) const { SkScalar marginWidth = fBox.width(); - if (marginWidth <= 0 || len == 0) - return; + if (marginWidth <= 0 || len == 0) { + return fBox.top(); + } const char* textStop = text + len; @@ -200,8 +199,7 @@ void SkTextBox::draw(SkCanvas* canvas, const char text[], size_t len, const SkPa { SkScalar textHeight = fontHeight; - if (fMode == kLineBreak_Mode && fSpacingAlign != kStart_SpacingAlign) - { + if (fMode == kLineBreak_Mode && fSpacingAlign != kStart_SpacingAlign) { int count = SkTextLineBreaker::CountLines(text, textStop - text, paint, marginWidth); SkASSERT(count > 0); textHeight += scaledSpacing * (count - 1); @@ -222,29 +220,48 @@ void SkTextBox::draw(SkCanvas* canvas, const char text[], size_t len, const SkPa y += fBox.fTop - metrics.fAscent; } - for (;;) - { + for (;;) { size_t trailing; len = linebreak(text, textStop, paint, marginWidth, &trailing); - if (y + metrics.fDescent + metrics.fLeading > 0) - canvas->drawText(text, len - trailing, x, y, paint); + if (y + metrics.fDescent + metrics.fLeading > 0) { + visitor(text, len - trailing, x, y, paint); + } text += len; - if (text >= textStop) + if (text >= textStop) { break; + } y += scaledSpacing; - if (y + metrics.fAscent >= fBox.fBottom) + if (y + metrics.fAscent >= fBox.fBottom) { break; + } } + return y + metrics.fDescent + metrics.fLeading; } /////////////////////////////////////////////////////////////////////////////// +class CanvasVisitor : public SkTextBox::Visitor { + SkCanvas* fCanvas; +public: + CanvasVisitor(SkCanvas* canvas) : fCanvas(canvas) {} + + virtual void operator()(const char text[], size_t length, SkScalar x, SkScalar y, + const SkPaint& paint) SK_OVERRIDE { + fCanvas->drawText(text, length, x, y, paint); + } +}; + void SkTextBox::setText(const char text[], size_t len, const SkPaint& paint) { fText = text; fLen = len; fPaint = &paint; } +void SkTextBox::draw(SkCanvas* canvas, const char text[], size_t len, const SkPaint& paint) { + CanvasVisitor sink(canvas); + this->visit(sink, text, len, paint); +} + void SkTextBox::draw(SkCanvas* canvas) { this->draw(canvas, fText, fLen, *fPaint); } @@ -257,3 +274,30 @@ SkScalar SkTextBox::getTextHeight() const { SkScalar spacing = SkScalarMul(fPaint->getTextSize(), fSpacingMul) + fSpacingAdd; return this->countLines() * spacing; } + +/////////////////////////////////////////////////////////////////////////////// + +#include "SkTextBlob.h" + +class TextBlobVisitor : public SkTextBox::Visitor { +public: + SkTextBlobBuilder fBuilder; + + virtual void operator()(const char text[], size_t length, SkScalar x, SkScalar y, + const SkPaint& paint) SK_OVERRIDE { + SkPaint p(paint); + p.setTextEncoding(SkPaint::kGlyphID_TextEncoding); + const int count = paint.countText(text, length); + paint.textToGlyphs(text, length, fBuilder.allocRun(p, count, x, y).glyphs); + } +}; + +SkTextBlob* SkTextBox::snapshotTextBlob(SkScalar* computedBottom) const { + TextBlobVisitor visitor; + SkScalar newB = this->visit(visitor, fText, fLen, *fPaint); + if (computedBottom) { + *computedBottom = newB; + } + return (SkTextBlob*)visitor.fBuilder.build(); +} + -- cgit v1.2.3