1/*
2 * Copyright 2011 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 "gm.h"
9#include "SkCanvas.h"
10#include "SkPath.h"
11#include "SkGradientShader.h"
12#include "SkTypeface.h"
13
14static SkShader* make_heatGradient(const SkPoint pts[2]) {
15    const SkColor colors[] = {
16        SK_ColorBLACK, SK_ColorBLUE, SK_ColorCYAN, SK_ColorGREEN,
17        SK_ColorYELLOW, SK_ColorRED, SK_ColorWHITE
18    };
19    const SkColor bw[] = { SK_ColorBLACK, SK_ColorWHITE };
20
21    return SkGradientShader::CreateLinear(pts, bw, NULL,
22                                          SK_ARRAY_COUNT(bw),
23                                          SkShader::kClamp_TileMode);
24}
25
26static bool setFont(SkPaint* paint, const char name[]) {
27    SkTypeface* tf = SkTypeface::CreateFromName(name, SkTypeface::kNormal);
28    if (tf) {
29        paint->setTypeface(tf)->unref();
30        return true;
31    }
32    return false;
33}
34
35#ifdef SK_BUILD_FOR_MAC
36#import <ApplicationServices/ApplicationServices.h>
37#define BITMAP_INFO_RGB     (kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Host)
38
39static CGContextRef makeCG(const SkBitmap& bm) {
40    if (SkBitmap::kARGB_8888_Config != bm.config() ||
41        NULL == bm.getPixels()) {
42        return NULL;
43    }
44    CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
45    CGContextRef cg = CGBitmapContextCreate(bm.getPixels(), bm.width(), bm.height(),
46                                            8, bm.rowBytes(), space, BITMAP_INFO_RGB);
47    CFRelease(space);
48
49    CGContextSetAllowsFontSubpixelQuantization(cg, false);
50    CGContextSetShouldSubpixelQuantizeFonts(cg, false);
51
52    return cg;
53}
54
55extern CTFontRef SkTypeface_GetCTFontRef(const SkTypeface* face);
56
57static CGFontRef typefaceToCGFont(const SkTypeface* face) {
58    if (NULL == face) {
59        return 0;
60    }
61
62    CTFontRef ct = SkTypeface_GetCTFontRef(face);
63    return CTFontCopyGraphicsFont(ct, NULL);
64}
65
66static void cgSetPaintForText(CGContextRef cg, const SkPaint& paint) {
67    SkColor c = paint.getColor();
68    CGFloat rgba[] = {
69        SkColorGetB(c) / 255.0,
70        SkColorGetG(c) / 255.0,
71        SkColorGetR(c) / 255.0,
72        SkColorGetA(c) / 255.0,
73    };
74    CGContextSetRGBFillColor(cg, rgba[0], rgba[1], rgba[2], rgba[3]);
75
76    CGContextSetTextDrawingMode(cg, kCGTextFill);
77    CGContextSetFont(cg, typefaceToCGFont(paint.getTypeface()));
78    CGContextSetFontSize(cg, SkScalarToFloat(paint.getTextSize()));
79
80    CGContextSetAllowsFontSubpixelPositioning(cg, paint.isSubpixelText());
81    CGContextSetShouldSubpixelPositionFonts(cg, paint.isSubpixelText());
82
83    CGContextSetShouldAntialias(cg, paint.isAntiAlias());
84    CGContextSetShouldSmoothFonts(cg, paint.isLCDRenderText());
85}
86
87static void cgDrawText(CGContextRef cg, const void* text, size_t len,
88                       float x, float y, const SkPaint& paint) {
89    if (cg) {
90        cgSetPaintForText(cg, paint);
91
92        uint16_t glyphs[200];
93        int count = paint.textToGlyphs(text, len, glyphs);
94
95        CGContextShowGlyphsAtPoint(cg, x, y, glyphs, count);
96    }
97}
98#endif
99
100namespace skiagm {
101
102/**
103   Test a set of clipping problems discovered while writing blitAntiRect,
104   and test all the code paths through the clipping blitters.
105   Each region should show as a blue center surrounded by a 2px green
106   border, with no red.
107*/
108
109#define HEIGHT 480
110
111class GammaTextGM : public GM {
112public:
113    GammaTextGM() {
114
115    }
116
117protected:
118    virtual SkString onShortName() {
119        return SkString("gammatext");
120    }
121
122    virtual SkISize onISize() {
123        return make_isize(1024, HEIGHT);
124    }
125
126    static void drawGrad(SkCanvas* canvas) {
127        SkPoint pts[] = { { 0, 0 }, { 0, HEIGHT } };
128#if 0
129        const SkColor colors[] = { SK_ColorBLACK, SK_ColorWHITE };
130        SkShader* s = SkGradientShader::CreateLinear(pts, colors, NULL, 2, SkShader::kClamp_TileMode);
131#else
132        SkShader* s = make_heatGradient(pts);
133#endif
134
135        canvas->clear(SK_ColorRED);
136        SkPaint paint;
137        paint.setShader(s)->unref();
138        SkRect r = { 0, 0, 1024, HEIGHT };
139        canvas->drawRect(r, paint);
140    }
141
142    virtual void onDraw(SkCanvas* canvas) {
143#ifdef SK_BUILD_FOR_MAC
144        CGContextRef cg = makeCG(canvas->getDevice()->accessBitmap(false));
145#endif
146
147        drawGrad(canvas);
148
149        const SkColor fg[] = {
150            0xFFFFFFFF,
151            0xFFFFFF00, 0xFFFF00FF, 0xFF00FFFF,
152            0xFFFF0000, 0xFF00FF00, 0xFF0000FF,
153            0xFF000000,
154        };
155
156        const char* text = "Hamburgefons";
157        size_t len = strlen(text);
158
159        SkPaint paint;
160        setFont(&paint, "Times");
161        paint.setTextSize(SkIntToScalar(16));
162        paint.setAntiAlias(true);
163        paint.setLCDRenderText(true);
164
165        SkScalar x = 10;
166        for (size_t i = 0; i < SK_ARRAY_COUNT(fg); ++i) {
167            paint.setColor(fg[i]);
168
169            SkScalar y = 40;
170            SkScalar stopy = HEIGHT;
171            while (y < stopy) {
172#if 1
173                canvas->drawText(text, len, x, y, paint);
174#else
175                cgDrawText(cg, text, len, x, HEIGHT - y, paint);
176#endif
177                y += paint.getTextSize() * 2;
178            }
179            x += SkIntToScalar(1024) / SK_ARRAY_COUNT(fg);
180        }
181    }
182
183private:
184    typedef GM INHERITED;
185};
186
187//////////////////////////////////////////////////////////////////////////////
188
189static GM* MyFactory(void*) { return new GammaTextGM; }
190static GMRegistry reg(MyFactory);
191
192}
193