blob: 3cbc8a35ad8cd1d80d6fe595ed3aa0c3adeb4253 [file] [log] [blame]
joshualitte49109f2015-07-17 12:47:39 -07001/*
2 * Copyright 2015 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "sk_tool_utils.h"
9#include "SkCanvas.h"
10#include "SkPaint.h"
11#include "SkPoint.h"
12#include "SkTextBlob.h"
13#include "SkFontMgr.h"
14#include "SkGraphics.h"
15#include "SkSurface.h"
16#include "SkTypeface.h"
17
18#ifdef SK_BUILD_FOR_WIN
19 #include "SkTypeface_win.h"
20#endif
21
22#include "Test.h"
23
24#if SK_SUPPORT_GPU
25#include "GrContextFactory.h"
26
27struct TextBlobWrapper {
joshualittbedf7e52015-07-23 08:09:35 -070028 // This class assumes it 'owns' the textblob it wraps, and thus does not need to take a ref
29 explicit TextBlobWrapper(const SkTextBlob* blob) : fBlob(blob) {}
joshualitte49109f2015-07-17 12:47:39 -070030 TextBlobWrapper(const TextBlobWrapper& blob) : fBlob(SkRef(blob.fBlob.get())) {}
31
32 SkAutoTUnref<const SkTextBlob> fBlob;
33};
34
35static void draw(SkCanvas* canvas, int redraw, const SkTArray<TextBlobWrapper>& blobs) {
joshualitt404d9d62015-07-22 11:00:32 -070036 int yOffset = 0;
joshualitte49109f2015-07-17 12:47:39 -070037 for (int r = 0; r < redraw; r++) {
38 for (int i = 0; i < blobs.count(); i++) {
joshualitt404d9d62015-07-22 11:00:32 -070039 const SkTextBlob* blob = blobs[i].fBlob.get();
40 const SkRect& bounds = blob->bounds();
41 yOffset += SkScalarCeilToInt(bounds.height());
joshualitte49109f2015-07-17 12:47:39 -070042 SkPaint paint;
joshualitt404d9d62015-07-22 11:00:32 -070043 canvas->drawTextBlob(blob, 0, SkIntToScalar(yOffset), paint);
joshualitte49109f2015-07-17 12:47:39 -070044 }
45 }
46}
47
48// limit this just so we don't take too long to draw
49#define MAX_TOTAL_TEXT 4096
50#define MAX_CHAR 256
joshualitt11dfc8e2015-07-23 08:30:25 -070051#define MAX_FAMILIES 30
52
53static const int kWidth = 1024;
54static const int kHeight = 768;
joshualitte49109f2015-07-17 12:47:39 -070055
56// This test hammers the GPU textblobcache and font atlas
joshualitt404d9d62015-07-22 11:00:32 -070057DEF_GPUTEST(TextBlobCache, reporter, factory) {
joshualitte49109f2015-07-17 12:47:39 -070058 // setup surface
59 uint32_t flags = 0;
60 SkSurfaceProps props(flags, SkSurfaceProps::kLegacyFontHost_InitType);
61
joshualitt404d9d62015-07-22 11:00:32 -070062 GrContext* ctx = factory->get(GrContextFactory::kNative_GLContextType);
joshualitt11dfc8e2015-07-23 08:30:25 -070063 SkImageInfo info = SkImageInfo::Make(kWidth, kHeight, kN32_SkColorType, kPremul_SkAlphaType);
joshualitte49109f2015-07-17 12:47:39 -070064 SkAutoTUnref<SkSurface> surface(SkSurface::NewRenderTarget(ctx, SkSurface::kNo_Budgeted, info,
65 0, &props));
66 REPORTER_ASSERT(reporter, surface);
67 if (!surface) {
68 return;
69 }
70
71 SkCanvas* canvas = surface->getCanvas();
72
73 SkAutoTUnref<SkFontMgr> fm(SkFontMgr::RefDefault());
74
75 int count = SkMin32(fm->countFamilies(), MAX_FAMILIES);
76
77 // make a ton of text
78 uint16_t text[MAX_TOTAL_TEXT];
79 for (int i = 0; i < MAX_TOTAL_TEXT; i++) {
80 text[i] = i % MAX_CHAR;
81 }
82
83 // generate textblobs
84 SkTArray<TextBlobWrapper> blobs;
85 for (int i = 0; i < count; i++) {
86 SkPaint paint;
87 paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
joshualitt11dfc8e2015-07-23 08:30:25 -070088 paint.setTextSize(48); // draw big glyphs to really stress the atlas
joshualitte49109f2015-07-17 12:47:39 -070089
90 SkString familyName;
91 fm->getFamilyName(i, &familyName);
92 SkAutoTUnref<SkFontStyleSet> set(fm->createStyleSet(i));
93 for (int j = 0; j < set->count(); ++j) {
94 SkFontStyle fs;
95 set->getStyle(j, &fs, NULL);
96
97 SkSafeUnref(paint.setTypeface(set->createTypeface(j)));
98
99 SkTextBlobBuilder builder;
100 for (int aa = 0; aa < 2; aa++) {
101 for (int subpixel = 0; subpixel < 2; subpixel++) {
102 for (int lcd = 0; lcd < 2; lcd++) {
103 paint.setAntiAlias(SkToBool(aa));
104 paint.setSubpixelText(SkToBool(subpixel));
105 paint.setLCDRenderText(SkToBool(lcd));
106 const SkTextBlobBuilder::RunBuffer& run = builder.allocRun(paint,
107 MAX_TOTAL_TEXT,
108 0, 0,
109 NULL);
110 memcpy(run.glyphs, text, MAX_TOTAL_TEXT * sizeof(uint16_t));
111 }
112 }
113 }
114 SkNEW_APPEND_TO_TARRAY(&blobs, TextBlobWrapper, (builder.build()));
115 }
116 }
117
joshualitt11dfc8e2015-07-23 08:30:25 -0700118 // create surface where LCD is impossible
119 info = SkImageInfo::MakeN32Premul(kWidth, kHeight);
120 SkSurfaceProps propsNoLCD(0, kUnknown_SkPixelGeometry);
121 SkAutoTUnref<SkSurface> surfaceNoLCD(canvas->newSurface(info, &propsNoLCD));
122 REPORTER_ASSERT(reporter, surface);
123 if (!surface) {
124 return;
125 }
126
127 SkCanvas* canvasNoLCD = surfaceNoLCD->getCanvas();
128
joshualitte49109f2015-07-17 12:47:39 -0700129 // test redraw
130 draw(canvas, 2, blobs);
joshualitt11dfc8e2015-07-23 08:30:25 -0700131 draw(canvasNoLCD, 2, blobs);
joshualitte49109f2015-07-17 12:47:39 -0700132
133 // test draw after free
134 ctx->freeGpuResources();
135 draw(canvas, 1, blobs);
136
joshualitt11dfc8e2015-07-23 08:30:25 -0700137 ctx->freeGpuResources();
138 draw(canvasNoLCD, 1, blobs);
139
joshualitte49109f2015-07-17 12:47:39 -0700140 // test draw after abandon
141 ctx->abandonContext();
142 draw(canvas, 1, blobs);
143}
144#endif