diff options
author | The Android Open Source Project <initial-contribution@android.com> | 2009-01-09 17:51:21 -0800 |
---|---|---|
committer | The Android Open Source Project <initial-contribution@android.com> | 2009-01-09 17:51:21 -0800 |
commit | 03202c9c3dfbf8c4feb0a1ee9b3680817e633f58 (patch) | |
tree | 1d0ba7cbf3e77c239527697ac455312b216c434e /samplecode/SampleText.cpp | |
parent | 37df15a82319228ae28fe5d99c010b288aad7091 (diff) | |
download | external_skia-03202c9c3dfbf8c4feb0a1ee9b3680817e633f58.zip external_skia-03202c9c3dfbf8c4feb0a1ee9b3680817e633f58.tar.gz external_skia-03202c9c3dfbf8c4feb0a1ee9b3680817e633f58.tar.bz2 |
auto import from //branches/cupcake/...@125939
Diffstat (limited to 'samplecode/SampleText.cpp')
-rw-r--r-- | samplecode/SampleText.cpp | 791 |
1 files changed, 791 insertions, 0 deletions
diff --git a/samplecode/SampleText.cpp b/samplecode/SampleText.cpp new file mode 100644 index 0000000..60e015a --- /dev/null +++ b/samplecode/SampleText.cpp @@ -0,0 +1,791 @@ +#include "SampleCode.h" +#include "SkView.h" +#include "SkCanvas.h" +#include "Sk64.h" +#include "SkGradientShader.h" +#include "SkGraphics.h" +#include "SkImageDecoder.h" +#include "SkKernel33MaskFilter.h" +#include "SkPath.h" +#include "SkRandom.h" +#include "SkRegion.h" +#include "SkShader.h" +#include "SkUtils.h" +#include "SkColorPriv.h" +#include "SkColorFilter.h" +#include "SkTime.h" +#include "SkTypeface.h" +#include "SkXfermode.h" + +#include "SkStream.h" +#include "SkXMLParser.h" + +static const int gKernel[3][3] = { +// { -1, -2, -1 }, { -2, 12, -2 }, { -1, -2, -1 } + { 1, 2, 1 }, { 2, 64-12, 2 }, { 1, 2, 1 } +}; +static const int gShift = 6; + +class ReduceNoise : public SkKernel33ProcMaskFilter { +public: + ReduceNoise(int percent256) : SkKernel33ProcMaskFilter(percent256) {} + virtual uint8_t computeValue(uint8_t* const* srcRows) + { + int c = srcRows[1][1]; + int min = 255, max = 0; + for (int i = 0; i < 3; i++) + for (int j = 0; j < 3; j++) + if (i != 1 || j != 1) + { + int v = srcRows[i][j]; + if (max < v) + max = v; + if (min > v) + min = v; + } + if (c > max) c = max; + // if (c < min) c = min; + return c; + } + virtual Factory getFactory() { return Create; } +private: + ReduceNoise(SkFlattenableReadBuffer& rb) : SkKernel33ProcMaskFilter(rb) {} + static SkFlattenable* Create(SkFlattenableReadBuffer& rb) + { + return new ReduceNoise(rb); + } +}; + +class Darken : public SkKernel33ProcMaskFilter { +public: + Darken(int percent256) : SkKernel33ProcMaskFilter(percent256) {} + virtual uint8_t computeValue(uint8_t* const* srcRows) + { + int c = srcRows[1][1]; + float f = c / 255.f; + + if (c >= 0) + { + f = sqrtf(f); + } + else + { + f *= f; + } + SkASSERT(f >= 0 && f <= 1); + return (int)(f * 255); + } + virtual Factory getFactory() { return Create; } +private: + Darken(SkFlattenableReadBuffer& rb) : SkKernel33ProcMaskFilter(rb) {} + static SkFlattenable* Create(SkFlattenableReadBuffer& rb) + { + return new Darken(rb); + } +}; + +static SkMaskFilter* makemf() { return new Darken(0x30); } + +//#ifdef TEST_CLICKX + +static void test_typefaceCache() +{ + SkTypeface* t0 = SkTypeface::Create("sans-serif", SkTypeface::kNormal); + SkTypeface* t1 = SkTypeface::Create(NULL, SkTypeface::kNormal); + SkTypeface* t2 = SkTypeface::Create("arial", SkTypeface::kNormal); + SkTypeface* t3 = SkTypeface::Create("helvetica", SkTypeface::kItalic); + +#ifndef SK_BUILD_FOR_MAC + SkASSERT(t0 == t1); + SkASSERT(t0 == t2); + SkASSERT(t0 == t3); +#endif +} + +static void test_breakText() +{ + SkPaint paint; + const char* text = "sdfkljAKLDFJKEWkldfjlk#$%&sdfs.dsj"; + size_t length = strlen(text); + SkScalar width = paint.measureText(text, length); + + SkScalar mm = 0; + SkScalar nn = 0; + for (SkScalar w = 0; w <= width; w += SK_Scalar1) + { + SkScalar m; + size_t n = paint.breakText(text, length, w, &m, + SkPaint::kBackward_TextBufferDirection); + + SkASSERT(n <= length); + SkASSERT(m <= width); + + if (n == 0) + SkASSERT(m == 0); + else + { + // now assert that we're monotonic + if (n == nn) + SkASSERT(m == mm); + else + { + SkASSERT(n > nn); + SkASSERT(m > mm); + } + } + nn = n; + mm = m; + } + + nn = paint.breakText(text, length, width, &mm); + SkASSERT(nn == length); + SkASSERT(mm == width); +} + +static SkRandom gRand; + +class SkPowerMode : public SkXfermode { +public: + SkPowerMode(SkScalar exponent) { this->init(exponent); } + + virtual void xfer16(uint16_t dst[], const SkPMColor src[], int count, const SkAlpha aa[]); + + typedef SkFlattenable* (*Factory)(SkFlattenableReadBuffer&); + + // overrides for SkFlattenable + virtual Factory getFactory() { return Create; } + virtual void flatten(SkFlattenableWriteBuffer& b) + { + // this->INHERITED::flatten(b); How can we know if this is legal???? + b.write32(SkScalarToFixed(fExp)); + } + +private: + SkScalar fExp; // user's value + uint8_t fTable[256]; // cache + + void init(SkScalar exponent); + SkPowerMode(SkFlattenableReadBuffer& b) : SkXfermode(b) + { + // read the exponent + this->init(SkFixedToScalar(b.readS32())); + } + static SkFlattenable* Create(SkFlattenableReadBuffer& b) + { + return SkNEW_ARGS(SkPowerMode, (b)); + } + + typedef SkXfermode INHERITED; +}; + +void SkPowerMode::init(SkScalar e) +{ + fExp = e; + float ee = SkScalarToFloat(e); + + printf("------ %g\n", ee); + for (int i = 0; i < 256; i++) + { + float x = i / 255.f; + // printf(" %d %g", i, x); + x = powf(x, ee); + // printf(" %g", x); + int xx = SkScalarRound(SkFloatToScalar(x * 255)); + // printf(" %d\n", xx); + fTable[i] = SkToU8(xx); + } +} + +void SkPowerMode::xfer16(uint16_t dst[], const SkPMColor src[], int count, const SkAlpha aa[]) +{ + for (int i = 0; i < count; i++) + { + SkPMColor c = src[i]; + int r = SkGetPackedR32(c); + int g = SkGetPackedG32(c); + int b = SkGetPackedB32(c); + r = fTable[r]; + g = fTable[g]; + b = fTable[b]; + dst[i] = SkPack888ToRGB16(r, g, b); + } +} + +static const struct { + const char* fName; + uint32_t fFlags; + bool fFlushCache; +} gHints[] = { + { "Linear", SkPaint::kLinearText_Flag, false }, + { "Normal", 0, true }, + { "Subpixel", SkPaint::kSubpixelText_Flag, true } +}; + +#ifdef SK_DEBUG + #define REPEAT_COUNT 1 +#else + #define REPEAT_COUNT 5000 +#endif + +static int count_char_points(const SkPaint& paint, char c) +{ + SkPath path; + + paint.getTextPath(&c, 1, 0, 0, &path); + return path.getPoints(NULL, 0); +} + +static int gOld, gNew, gCount; + +static void dump(int c, int oldc, int newc) +{ + if (oldc != newc) + { + gOld += oldc; + gNew += newc; + gCount += 1; + printf("char %c: old = %3d, new = %3d, reduction %g%%\n", c, oldc, newc, 100. * (oldc - newc) / oldc); + } +} + +static void tab(int n) +{ +// printf("[%d] ", n); return; + SkASSERT(n >= 0); + for (int i = 0; i < n; i++) + printf(" "); +} + +#if 0 +#include "badrects.cpp" + +static void make_badrgn(SkRegion* rgn, int insetAmount) +{ + SkRect16 r, bounds; + int i; + + rgn->setEmpty(); + bounds.setEmpty(); + + for (i = 0; i < SK_ARRAY_COUNT(badrects); i++) + { + SkASSERT(badrects[i].width > 0 && badrects[i].height > 0); + + r.set(badrects[i].x, badrects[i].y, badrects[i].x + badrects[i].width, badrects[i].y + badrects[i].height); + r.inset(insetAmount, insetAmount); + rgn->op(r, SkRegion::kUnion_Op); + bounds.join(r); + } + SkASSERT(bounds == rgn->getBounds()); + + for (i = 0; i < SK_ARRAY_COUNT(badrects); i++) + { + r.set(badrects[i].x, badrects[i].y, badrects[i].x + badrects[i].width, badrects[i].y + badrects[i].height); + SkASSERT(rgn->contains(r)); + } +} +#endif + +static void draw_rgn(const SkRegion& rgn, SkCanvas* canvas, const SkPaint& paint) +{ + SkRect r; + SkRegion::Iterator iter(rgn); + + for (; !iter.done(); iter.next()) + { + r.set(iter.rect()); + canvas->drawRect(r, paint); + } +} + +static void test_break(SkCanvas* canvas, const char text[], size_t length, + SkScalar x, SkScalar y, const SkPaint& paint, + SkScalar clickX) +{ + SkPaint linePaint; + + linePaint.setAntiAlias(true); + + SkScalar measured; + + if (paint.breakText(text, length, clickX - x, &measured, SkPaint::kForward_TextBufferDirection)) + { + linePaint.setColor(SK_ColorRED); + canvas->drawLine(x, y, x + measured, y, linePaint); + } + + x += paint.measureText(text, length); + if (paint.breakText(text, length, x - clickX, &measured, SkPaint::kBackward_TextBufferDirection)) + { + linePaint.setColor(SK_ColorBLUE); + canvas->drawLine(x - measured, y, x, y, linePaint); + } +} + +static void test_poly() +{ + static const SkPoint dst[] = { + SkIntToScalar(2), SkIntToScalar(1), + SkIntToScalar(5), SkIntToScalar(1), + SkIntToScalar(5), SkIntToScalar(3), + SkIntToScalar(2), SkIntToScalar(3) + }; + + static const SkPoint src[] = { + SkIntToScalar(0), SkIntToScalar(0), + SkIntToScalar(1), SkIntToScalar(0), + SkIntToScalar(1), SkIntToScalar(1), + SkIntToScalar(0), SkIntToScalar(1) + }; + + SkMatrix matrix; + + if (matrix.setPolyToPoly(src, dst, 4)) + { + SkPoint pt = { SK_Scalar1/2, SK_Scalar1/2 }; + matrix.mapPoints(&pt, 1); + printf("---- x = %g y = %g\n", SkScalarToFloat(pt.fX), SkScalarToFloat(pt.fY)); + } + else + printf("---- setPolyToPoly failed\n"); +} + +#include "SkColorShader.h" + +static void DrawTheText(SkCanvas* canvas, const char text[], size_t length, + SkScalar x, SkScalar y, const SkPaint& paint, + SkScalar clickX, SkMaskFilter* mf) +{ + SkPaint p(paint); + +#if 0 + canvas->drawText(text, length, x, y, paint); +#else + { + SkPoint pts[1000]; + SkScalar xpos = x; + SkASSERT(length <= SK_ARRAY_COUNT(pts)); + for (size_t i = 0; i < length; i++) + pts[i].set(xpos, y), xpos += paint.getTextSize(); + canvas->drawPosText(text, length, pts, paint); + } +#endif + + p.setSubpixelText(true); + x += SkIntToScalar(180); + canvas->drawText(text, length, x, y, p); + +#ifdef TEST_CLICKX + test_break(canvas, text, length, x, y, p, clickX); +#endif + +#ifdef SK_DEBUG + if (false) + { + SkColorShader shader; + p.setShader(&shader); + x += SkIntToScalar(180); + canvas->drawText(text, length, x, y, p); + p.setShader(NULL); + } + + if (true) + { + // p.setMaskFilter(mf); + p.setSubpixelText(false); + p.setLinearText(true); + x += SkIntToScalar(180); + canvas->drawText(text, length, x, y, p); + } +#endif +} + +class TextSpeedView : public SkView { +public: + TextSpeedView() + { + fMF = makemf(); + + fHints = 0; + + if (false) + { + static const char extra[] = { '.', ',', ':', ';', '!' }; + SkPaint paint, paint2; + + paint2.setTypeface(SkTypeface::Create(NULL, SkTypeface::kItalic))->unref(); + + for (int i = 0; i < 26; i++) + ::dump('a' + i, count_char_points(paint, 'a' + i), count_char_points(paint2, 'a' + i)); + for (int j = 0; j < SK_ARRAY_COUNT(extra); j++) + ::dump(extra[j], count_char_points(paint, extra[j]), count_char_points(paint2, extra[j])); + + printf("--- ave reduction = %g%%\n", 100. * (gOld - gNew) / gOld); + } + + if (true) + { + SkPoint pts[] = { SkIntToScalar(20), 0, SkIntToScalar(256+20), 0 }; + SkColor colors[] = { SkColorSetARGB(0, 255, 255, 255), SkColorSetARGB(255, 255, 255, 255) }; + fGradient = SkGradientShader::CreateLinear(pts, colors, NULL, 2, SkShader::kClamp_TileMode); + } + + fClickX = 0; + + test_breakText(); + test_typefaceCache(); + test_poly(); + } + + virtual ~TextSpeedView() + { + fGradient->unref(); + fMF->safeUnref(); + } + +protected: + // overrides from SkEventSink + virtual bool onQuery(SkEvent* evt) + { + if (SampleCode::TitleQ(*evt)) + { + SampleCode::TitleR(evt, "Text"); + return true; + } + return this->INHERITED::onQuery(evt); + } + + void drawBG(SkCanvas* canvas) + { +// canvas->drawColor(0xFFDDDDDD); + canvas->drawColor(SK_ColorWHITE); + // canvas->drawColor(SK_ColorBLACK); + } + + static void make_textstrip(SkBitmap* bm) + { + bm->setConfig(SkBitmap::kRGB_565_Config, 200, 18); + bm->allocPixels(); + bm->eraseColor(SK_ColorWHITE); + + SkCanvas canvas(*bm); + SkPaint paint; + const char* s = "Lorem ipsum dolor sit amet, consectetuer adipiscing elit"; + + paint.setFlags(paint.getFlags() | SkPaint::kAntiAlias_Flag + | SkPaint::kDevKernText_Flag); + paint.setTextSize(SkIntToScalar(14)); + canvas.drawText(s, strlen(s), SkIntToScalar(8), SkIntToScalar(14), paint); + } + + static void fill_pts(SkPoint pts[], size_t n, SkRandom* rand) + { + for (size_t i = 0; i < n; i++) + pts[i].set(rand->nextUScalar1() * 640, rand->nextUScalar1() * 480); + } + + virtual void onDraw(SkCanvas* canvas) + { + if (false) + { + canvas->translate(SkIntToScalar(480), 0); + canvas->rotate(SkIntToScalar(90)); + } + + this->drawBG(canvas); + + if (false) + { + SkPaint p; + + p.setAntiAlias(true); + p.setSubpixelText(true); + // p.setLinearText(true); + + SkScalar size = SkIntToScalar(6); + SkMSec dur = 0; + const int LOOP = 16; + const int TIMES = 10; + + for (int times = 0; times < TIMES; times++) + { + SkMSec now = SkTime::GetMSecs(); + for (int loop = 0; loop < LOOP; loop++) + { + p.setTextSize(size); + size += SK_Scalar1/5; + canvas->drawText("Hamburgefons", 12, SkIntToScalar(10), SkIntToScalar(50), p); + } + dur += SkTime::GetMSecs() - now; + SkGraphics::SetFontCacheUsed(0); + } + + printf("----- duration = %g\n", dur * 1.0 / TIMES); + this->inval(NULL); + return; + } + + if (false) + { + SkPaint p; + p.setAntiAlias(true); + for (int i = 6; i <= 36; i++) + { + SkRect r; + SkPaint::FontMetrics m; + p.setTextSize(SkIntToScalar(i)); + p.getFontMetrics(&m); + int ascent = SkScalarRound(m.fAscent); + int descent = SkScalarRound(m.fDescent); + for (uint8_t c = ' '; c <= 127; c++) + { + p.getTextWidths(&c, 1, NULL, &r); + if (SkScalarRound(r.fTop) < ascent) + printf("PS %d --- %c [%d] top=%g, ascent=%g ymax=%g\n", i, c, c, + SkScalarToFloat(r.fTop), SkScalarToFloat(m.fAscent), SkScalarToFloat(m.fTop)); + if (SkScalarRound(r.fBottom) > descent) + printf("PS %d --- %c [%d] bottom=%g, descent=%g ymin=%g\n", i, c, c, + SkScalarToFloat(r.fBottom), SkScalarToFloat(m.fDescent), SkScalarToFloat(m.fBottom)); + } + } + } + + if (false) + { + SkPaint p; + p.setShader(fGradient); + +#ifdef SK_RELEASE + SkMSec now = SkTime::GetMSecs(); + for (int i = 0; i < 100; i++) +#endif + canvas->drawPaint(p); +#ifdef SK_RELEASE + printf("----- %d ms\n", SkTime::GetMSecs() - now); + this->inval(NULL); +#endif + return; + } + + if (false) + { + SkBitmap bm; + + make_textstrip(&bm); + canvas->translate(0, SkIntToScalar(50)); + for (int i = 0; i < 10; i++) + { + float gamma = 1 + i * 0.2f; + SkPowerMode mode(SkFloatToScalar(1 / gamma)); + SkPaint p; + p.setXfermode(&mode); + + canvas->drawBitmap(bm, 0, SkIntToScalar(i) * bm.height(), &p); + } + return; + } + + if (false) + { + SkPaint paint; + + paint.setAntiAlias(true); + paint.setDevKernText(true); + SkMSec now = SkTime::GetMSecs(); + for (int i = 0; i < 1000000; i++) + { + paint.measureText("Hamburgefons", 15, NULL, NULL); + } + printf("--------- measure %d\n", SkTime::GetMSecs() - now); + this->inval(NULL); + return; + } + + if (false) + { + SkRegion rgn; + SkPath path; + SkPaint paint; + + // make_badrgn(&rgn, -2); + + if (false) + { + paint.setColor(SK_ColorBLUE); + canvas->drawIRect(rgn.getBounds(), paint); + } + paint.setColor(SK_ColorRED); + draw_rgn(rgn, canvas, paint); + + rgn.getBoundaryPath(&path); + paint.setARGB(0x80, 0, 0, 0xFF); + canvas->drawPath(path, paint); + return; + } + + if (false) + { + SkRect r = { SkIntToScalar(50), SkIntToScalar(50), SkIntToScalar(300), SkIntToScalar(300) }; + SkPaint p; + + p.setStyle(SkPaint::kStroke_Style); + p.setAlpha(0x80); + p.setStrokeWidth(SkIntToScalar(20)); + canvas->drawRect(r, p); + } + + if (false) + { + SkPaint p; + SkRect r = { SkIntToScalar(100), SkIntToScalar(100), SkIntToScalar(104), SkIntToScalar(104) }; + // r.offset(SK_ScalarHalf, SK_ScalarHalf); + p.setStyle(SkPaint::kStroke_Style); + p.setStrokeWidth(SK_Scalar1*2); + // p.setAntiAliasOn(true); + canvas->drawRect(r, p); + return; + } + + if (false) + { + Sk64 aa, bb; + int64_t a = (int64_t)6062080 * -30596; + int64_t b = (int64_t)4816896 * 57957; + aa.setMul(6062080, -30596); + bb.setMul(4816896, 57957); + + a += b; + b = a >> 16; + +// SkFixed c = aa.addGetFixed(bb); + + printf("%d %d\n", (int)a, a >> 32); + + SkBitmap bm; + SkPaint paint; + SkScalar scale = SkFloatToScalar(0.5625f); + SkScalar x = SkIntToScalar(100); + SkScalar y = SkIntToScalar(100); + + //paint.setFilterType(SkPaint::kBilinear_FilterType); + + SkImageDecoder::DecodeFile("/app_web_browser.png", &bm); + + // canvas->drawBitmap(bm, x, y, paint); + x += SkIntToScalar(100); + canvas->save(); + canvas->translate(x, y); + canvas->scale(SkIntToScalar(2)/1, SkIntToScalar(2)/1); + canvas->translate(-x, -y); + canvas->drawBitmap(bm, x, y, &paint); + canvas->restore(); + x += SkIntToScalar(100); + canvas->save(); + canvas->translate(x, y); + canvas->scale(scale, scale); + canvas->translate(-x, -y); + // canvas->drawBitmap(bm, x, y, paint); + canvas->restore(); + return; + } + + SkAutoCanvasRestore restore(canvas, false); + { + SkRect r; + r.set(0, 0, SkIntToScalar(1000), SkIntToScalar(20)); + // canvas->saveLayer(&r, NULL, SkCanvas::kHasAlphaLayer_SaveFlag); + } + + SkPaint paint; +// const uint16_t glyphs[] = { 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19 }; + int index = fHints % SK_ARRAY_COUNT(gHints); + index = 1; +// const char* style = gHints[index].fName; + +// canvas->translate(0, SkIntToScalar(50)); + + // canvas->drawText(style, strlen(style), SkIntToScalar(20), SkIntToScalar(20), paint); + +// paint.setTypeface(SkTypeface::Create(NULL, SkTypeface::kItalic))->unref(); + paint.setAntiAlias(true); + paint.setFlags(paint.getFlags() | gHints[index].fFlags); + + SkMSec now = 0; + if (REPEAT_COUNT > 1) + now = SkTime::GetMSecs(); + + SkRect clip; + clip.set(SkIntToScalar(25), SkIntToScalar(34), SkIntToScalar(88), SkIntToScalar(155)); + + if (0) { + canvas->clipRect(clip); + } + + if (0) { + SkPath clipPath; + clipPath.addOval(clip); + canvas->clipPath(clipPath); + } + + const char* text = "Hamburgefons"; + size_t length = strlen(text); + +#ifdef TEST_CLICKX + { + SkPaint p; + + p.setColor(SK_ColorGREEN); + p.setAntiAlias(true); + canvas->drawLine(fClickX, 0, fClickX, SkIntToScalar(1000), p); + } +#endif + + for (int j = 0; j < REPEAT_COUNT; j++) + { + SkScalar y = SkIntToScalar(0); + for (int i = 9; i <= 24; i++) { + paint.setTextSize(SkIntToScalar(i) /*+ (gRand.nextU() & 0xFFFF)*/); + for (SkScalar dx = 0; dx <= SkIntToScalar(3)/4; dx += SkIntToScalar(1) /* /4 */) + { + y += paint.getFontSpacing(); + DrawTheText(canvas, text, length, SkIntToScalar(20) + dx, y, paint, fClickX, fMF); + } + } + if (gHints[index].fFlushCache) { + SkGraphics::SetFontCacheUsed(0); + } + } + + if (REPEAT_COUNT > 1) + { + printf("--------- FPS = %g\n", REPEAT_COUNT * 1000. / (SkTime::GetMSecs() - now)); + this->inval(NULL); + } + } + + virtual SkView::Click* onFindClickHandler(SkScalar x, SkScalar y) + { + fClickX = x; + this->inval(NULL); + return this->INHERITED::onFindClickHandler(x, y); + } + + virtual bool onClick(Click* click) + { + return this->INHERITED::onClick(click); + } + +private: + int fHints; + SkScalar fClickX; + SkMaskFilter* fMF; + SkShader* fGradient; + + typedef SkView INHERITED; +}; + +////////////////////////////////////////////////////////////////////////////// + +static SkView* MyFactory() { return new TextSpeedView; } +static SkViewRegister reg(MyFactory); + |