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 14 static SkShader* make_heatGradient(const SkPoint pts[2]) { 15 #if 0 // UNUSED 16 const SkColor colors[] = { 17 SK_ColorBLACK, SK_ColorBLUE, SK_ColorCYAN, SK_ColorGREEN, 18 SK_ColorYELLOW, SK_ColorRED, SK_ColorWHITE 19 }; 20 #endif 21 const SkColor bw[] = { SK_ColorBLACK, SK_ColorWHITE }; 22 23 return SkGradientShader::CreateLinear(pts, bw, NULL, 24 SK_ARRAY_COUNT(bw), 25 SkShader::kClamp_TileMode); 26 } 27 28 static bool setFont(SkPaint* paint, const char name[]) { 29 SkTypeface* tf = sk_tool_utils::create_portable_typeface(name, SkTypeface::kNormal); 30 if (tf) { 31 paint->setTypeface(tf)->unref(); 32 return true; 33 } 34 return false; 35 } 36 37 #ifdef SK_BUILD_FOR_MAC 38 #import <ApplicationServices/ApplicationServices.h> 39 #define BITMAP_INFO_RGB (kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Host) 40 41 static CGContextRef makeCG(const SkImageInfo& info, const void* addr, 42 size_t rowBytes) { 43 if (kN32_SkColorType != info.colorType() || NULL == addr) { 44 return NULL; 45 } 46 CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB(); 47 CGContextRef cg = CGBitmapContextCreate((void*)addr, info.width(), info.height(), 48 8, rowBytes, space, BITMAP_INFO_RGB); 49 CFRelease(space); 50 51 CGContextSetAllowsFontSubpixelQuantization(cg, false); 52 CGContextSetShouldSubpixelQuantizeFonts(cg, false); 53 54 return cg; 55 } 56 57 extern CTFontRef SkTypeface_GetCTFontRef(const SkTypeface* face); 58 59 static CGFontRef typefaceToCGFont(const SkTypeface* face) { 60 if (NULL == face) { 61 return 0; 62 } 63 64 CTFontRef ct = SkTypeface_GetCTFontRef(face); 65 return CTFontCopyGraphicsFont(ct, NULL); 66 } 67 68 static void cgSetPaintForText(CGContextRef cg, const SkPaint& paint) { 69 SkColor c = paint.getColor(); 70 CGFloat rgba[] = { 71 SkColorGetB(c) / 255.0f, 72 SkColorGetG(c) / 255.0f, 73 SkColorGetR(c) / 255.0f, 74 SkColorGetA(c) / 255.0f, 75 }; 76 CGContextSetRGBFillColor(cg, rgba[0], rgba[1], rgba[2], rgba[3]); 77 78 CGContextSetTextDrawingMode(cg, kCGTextFill); 79 CGContextSetFont(cg, typefaceToCGFont(paint.getTypeface())); 80 CGContextSetFontSize(cg, SkScalarToFloat(paint.getTextSize())); 81 82 CGContextSetAllowsFontSubpixelPositioning(cg, paint.isSubpixelText()); 83 CGContextSetShouldSubpixelPositionFonts(cg, paint.isSubpixelText()); 84 85 CGContextSetShouldAntialias(cg, paint.isAntiAlias()); 86 CGContextSetShouldSmoothFonts(cg, paint.isLCDRenderText()); 87 } 88 89 static void cgDrawText(CGContextRef cg, const void* text, size_t len, 90 float x, float y, const SkPaint& paint) { 91 if (cg) { 92 cgSetPaintForText(cg, paint); 93 94 uint16_t glyphs[200]; 95 int count = paint.textToGlyphs(text, len, glyphs); 96 97 CGContextShowGlyphsAtPoint(cg, x, y, glyphs, count); 98 } 99 } 100 #endif 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 111 class GammaTextGM : public skiagm::GM { 112 public: 113 GammaTextGM() { 114 115 } 116 117 protected: 118 virtual SkString onShortName() { 119 return SkString("gammatext"); 120 } 121 122 virtual SkISize onISize() { 123 return SkISize::Make(1024, HEIGHT); 124 } 125 126 static void drawGrad(SkCanvas* canvas) { 127 SkPoint pts[] = { { 0, 0 }, { 0, SkIntToScalar(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, SkIntToScalar(1024), SkIntToScalar(HEIGHT) }; 139 canvas->drawRect(r, paint); 140 } 141 142 virtual void onDraw(SkCanvas* canvas) { 143 #ifdef SK_BUILD_FOR_MAC 144 CGContextRef cg = 0; 145 { 146 SkImageInfo info; 147 size_t rowBytes; 148 const void* addr = canvas->peekPixels(&info, &rowBytes); 149 if (addr) { 150 cg = makeCG(info, addr, rowBytes); 151 } 152 } 153 #endif 154 155 drawGrad(canvas); 156 157 const SkColor fg[] = { 158 0xFFFFFFFF, 159 0xFFFFFF00, 0xFFFF00FF, 0xFF00FFFF, 160 0xFFFF0000, 0xFF00FF00, 0xFF0000FF, 161 0xFF000000, 162 }; 163 164 const char* text = "Hamburgefons"; 165 size_t len = strlen(text); 166 167 SkPaint paint; 168 setFont(&paint, "Times"); 169 paint.setTextSize(SkIntToScalar(16)); 170 paint.setAntiAlias(true); 171 paint.setLCDRenderText(true); 172 173 SkScalar x = SkIntToScalar(10); 174 for (size_t i = 0; i < SK_ARRAY_COUNT(fg); ++i) { 175 paint.setColor(fg[i]); 176 177 SkScalar y = SkIntToScalar(40); 178 SkScalar stopy = SkIntToScalar(HEIGHT); 179 while (y < stopy) { 180 if (true) { 181 canvas->drawText(text, len, x, y, paint); 182 } 183 #ifdef SK_BUILD_FOR_MAC 184 else { 185 cgDrawText(cg, text, len, SkScalarToFloat(x), 186 static_cast<float>(HEIGHT) - SkScalarToFloat(y), 187 paint); 188 } 189 #endif 190 y += paint.getTextSize() * 2; 191 } 192 x += SkIntToScalar(1024) / SK_ARRAY_COUNT(fg); 193 } 194 #ifdef SK_BUILD_FOR_MAC 195 CGContextRelease(cg); 196 #endif 197 } 198 199 private: 200 typedef skiagm::GM INHERITED; 201 }; 202 203 DEF_GM( return new GammaTextGM; ) 204 205 ////////////////////////////////////////////////////////////////////////////// 206 207 static SkShader* make_gradient(SkColor c) { 208 const SkPoint pts[] = { { 0, 0 }, { 240, 0 } }; 209 SkColor colors[2]; 210 colors[0] = c; 211 colors[1] = SkColorSetA(c, 0); 212 return SkGradientShader::CreateLinear(pts, colors, NULL, 2, SkShader::kClamp_TileMode); 213 } 214 215 static void set_face(SkPaint* paint) { 216 SkTypeface* face = SkTypeface::CreateFromName("serif", SkTypeface::kItalic); 217 SkSafeUnref(paint->setTypeface(face)); 218 } 219 220 static void draw_pair(SkCanvas* canvas, SkPaint* paint, SkShader* shader) { 221 const char text[] = "Now is the time for all good"; 222 const size_t len = strlen(text); 223 224 paint->setShader(NULL); 225 canvas->drawText(text, len, 10, 20, *paint); 226 paint->setShader(SkShader::CreateColorShader(paint->getColor()))->unref(); 227 canvas->drawText(text, len, 10, 40, *paint); 228 paint->setShader(shader); 229 canvas->drawText(text, len, 10, 60, *paint); 230 } 231 232 class GammaShaderTextGM : public skiagm::GM { 233 SkShader* fShaders[3]; 234 SkColor fColors[3]; 235 236 public: 237 GammaShaderTextGM() { 238 const SkColor colors[] = { SK_ColorBLACK, SK_ColorRED, SK_ColorBLUE }; 239 for (size_t i = 0; i < SK_ARRAY_COUNT(fShaders); ++i) { 240 fShaders[i] = NULL; 241 fColors[i] = colors[i]; 242 } 243 } 244 245 virtual ~GammaShaderTextGM() { 246 for (size_t i = 0; i < SK_ARRAY_COUNT(fShaders); ++i) { 247 SkSafeUnref(fShaders[i]); 248 } 249 } 250 251 protected: 252 virtual SkString onShortName() { 253 return SkString("gammagradienttext"); 254 } 255 256 virtual SkISize onISize() { 257 return SkISize::Make(300, 300); 258 } 259 260 virtual void onOnceBeforeDraw() { 261 for (size_t i = 0; i < SK_ARRAY_COUNT(fShaders); ++i) { 262 fShaders[i] = make_gradient(fColors[i]); 263 } 264 } 265 266 virtual void onDraw(SkCanvas* canvas) { 267 SkPaint paint; 268 paint.setAntiAlias(true); 269 paint.setLCDRenderText(true); 270 paint.setTextSize(18); 271 set_face(&paint); 272 273 for (size_t i = 0; i < SK_ARRAY_COUNT(fShaders); ++i) { 274 paint.setColor(fColors[i]); 275 draw_pair(canvas, &paint, fShaders[i]); 276 canvas->translate(0, 80); 277 } 278 } 279 280 private: 281 typedef skiagm::GM INHERITED; 282 }; 283 284 DEF_GM( return new GammaShaderTextGM; ) 285 286