uint64_t GrPath::ComputeStrokeKey(const SkStrokeRec& stroke) { enum { kStyleBits = 2, kJoinBits = 2, kCapBits = 2, kWidthBits = 29, kMiterBits = 29, kJoinShift = kStyleBits, kCapShift = kJoinShift + kJoinBits, kWidthShift = kCapShift + kCapBits, kMiterShift = kWidthShift + kWidthBits, kBitCount = kMiterShift + kMiterBits }; SK_COMPILE_ASSERT(SkStrokeRec::kStyleCount <= (1 << kStyleBits), style_shift_will_be_wrong); SK_COMPILE_ASSERT(SkPaint::kJoinCount <= (1 << kJoinBits), cap_shift_will_be_wrong); SK_COMPILE_ASSERT(SkPaint::kCapCount <= (1 << kCapBits), miter_shift_will_be_wrong); SK_COMPILE_ASSERT(kBitCount == 64, wrong_stroke_key_size); if (!stroke.needToApply()) { return SkStrokeRec::kFill_Style; } uint64_t key = stroke.getStyle(); key |= stroke.getJoin() << kJoinShift; key |= stroke.getCap() << kCapShift; key |= get_top_n_float_bits<kWidthBits>(stroke.getWidth()) << kWidthShift; key |= get_top_n_float_bits<kMiterBits>(stroke.getMiter()) << kMiterShift; return key; }
void SkPDFGraphicState::emitObject(SkWStream* stream, const SkPDFObjNumMap& objNumMap, const SkPDFSubstituteMap& substitutes) { SkAutoTUnref<SkPDFDict> dict(SkNEW_ARGS(SkPDFDict, ("ExtGState"))); dict->insertName("Type", "ExtGState"); SkScalar alpha = SkScalarDiv(fAlpha, 0xFF); dict->insertScalar("CA", alpha); dict->insertScalar("ca", alpha); SkPaint::Cap strokeCap = (SkPaint::Cap)fStrokeCap; SkPaint::Join strokeJoin = (SkPaint::Join)fStrokeJoin; SkXfermode::Mode xferMode = (SkXfermode::Mode)fMode; SK_COMPILE_ASSERT(SkPaint::kButt_Cap == 0, paint_cap_mismatch); SK_COMPILE_ASSERT(SkPaint::kRound_Cap == 1, paint_cap_mismatch); SK_COMPILE_ASSERT(SkPaint::kSquare_Cap == 2, paint_cap_mismatch); SK_COMPILE_ASSERT(SkPaint::kCapCount == 3, paint_cap_mismatch); SkASSERT(strokeCap >= 0 && strokeCap <= 2); dict->insertInt("LC", strokeCap); SK_COMPILE_ASSERT(SkPaint::kMiter_Join == 0, paint_join_mismatch); SK_COMPILE_ASSERT(SkPaint::kRound_Join == 1, paint_join_mismatch); SK_COMPILE_ASSERT(SkPaint::kBevel_Join == 2, paint_join_mismatch); SK_COMPILE_ASSERT(SkPaint::kJoinCount == 3, paint_join_mismatch); SkASSERT(strokeJoin >= 0 && strokeJoin <= 2); dict->insertInt("LJ", strokeJoin); dict->insertScalar("LW", fStrokeWidth); dict->insertScalar("ML", fStrokeMiter); dict->insertBool("SA", true); // SA = Auto stroke adjustment. dict->insertName("BM", as_blend_mode(xferMode)); dict->emitObject(stream, objNumMap, substitutes); }
Key(const uint32_t uniqueID, const SkMatrix& matrix, const SkIRect& clipBounds, uint32_t srcGenID) : fUniqueID(uniqueID), fMatrix(matrix), fClipBounds(clipBounds), fSrcGenID(srcGenID) { // Assert that Key is tightly-packed, since it is hashed. SK_COMPILE_ASSERT(sizeof(Key) == sizeof(uint32_t) + sizeof(SkMatrix) + sizeof(SkIRect) + sizeof(uint32_t), image_filter_key_tight_packing); fMatrix.getType(); // force initialization of type, so hashes match }
GrPixelConfig GrBatchFontCache::getPixelConfig(GrMaskFormat format) const { static const GrPixelConfig kPixelConfigs[] = { kAlpha_8_GrPixelConfig, kRGB_565_GrPixelConfig, kSkia8888_GrPixelConfig }; SK_COMPILE_ASSERT(SK_ARRAY_COUNT(kPixelConfigs) == kMaskFormatCount, array_size_mismatch); return kPixelConfigs[format]; }
static GrPixelConfig mask_format_to_pixel_config(GrMaskFormat format) { static const GrPixelConfig sPixelConfigs[] = { kAlpha_8_GrPixelConfig, kRGB_565_GrPixelConfig, kSkia8888_GrPixelConfig }; SK_COMPILE_ASSERT(SK_ARRAY_COUNT(sPixelConfigs) == kMaskFormatCount, array_size_mismatch); return sPixelConfigs[format]; }
GrMaskFormat GrBatchFontCache::AtlasIndexToMaskFormat(int atlasIndex) { static GrMaskFormat sMaskFormats[] = { kA8_GrMaskFormat, kA565_GrMaskFormat, kARGB_GrMaskFormat, }; SK_COMPILE_ASSERT(SK_ARRAY_COUNT(sMaskFormats) == kMaskFormatCount, array_size_mismatch); SkASSERT(sMaskFormats[atlasIndex] < kMaskFormatCount); return sMaskFormats[atlasIndex]; }
int GrBatchFontCache::MaskFormatToAtlasIndex(GrMaskFormat format) { static const int sAtlasIndices[] = { kA8_GrMaskFormat, kA565_GrMaskFormat, kARGB_GrMaskFormat, }; SK_COMPILE_ASSERT(SK_ARRAY_COUNT(sAtlasIndices) == kMaskFormatCount, array_size_mismatch); SkASSERT(sAtlasIndices[format] < kMaskFormatCount); return sAtlasIndices[format]; }
static int mask_format_to_atlas_index(GrMaskFormat format) { static const int sAtlasIndices[] = { GrFontCache::kA8_AtlasType, GrFontCache::k565_AtlasType, GrFontCache::k8888_AtlasType }; SK_COMPILE_ASSERT(SK_ARRAY_COUNT(sAtlasIndices) == kMaskFormatCount, array_size_mismatch); SkASSERT(sAtlasIndices[format] < GrFontCache::kAtlasCount); return sAtlasIndices[format]; }
void SkResourceCache::Key::init(void* nameSpace, uint64_t sharedID, size_t length) { SkASSERT(SkAlign4(length) == length); // fCount32 and fHash are not hashed static const int kUnhashedLocal32s = 2; // fCache32 + fHash static const int kSharedIDLocal32s = 2; // fSharedID_lo + fSharedID_hi static const int kHashedLocal32s = kSharedIDLocal32s + (sizeof(fNamespace) >> 2); static const int kLocal32s = kUnhashedLocal32s + kHashedLocal32s; SK_COMPILE_ASSERT(sizeof(Key) == (kLocal32s << 2), unaccounted_key_locals); SK_COMPILE_ASSERT(sizeof(Key) == offsetof(Key, fNamespace) + sizeof(fNamespace), namespace_field_must_be_last); fCount32 = SkToS32(kLocal32s + (length >> 2)); fSharedID_lo = (uint32_t)sharedID; fSharedID_hi = (uint32_t)(sharedID >> 32); fNamespace = nameSpace; // skip unhashed fields when computing the murmur fHash = SkChecksum::Murmur3(this->as32() + kUnhashedLocal32s, (fCount32 - kUnhashedLocal32s) << 2); }
// populateDict and operator== have to stay in sync with each other. void SkPDFGraphicState::populateDict() { if (!fPopulated) { fPopulated = true; insertName("Type", "ExtGState"); SkRefPtr<SkPDFScalar> alpha = new SkPDFScalar(fPaint.getAlpha() * SkScalarInvert(0xFF)); alpha->unref(); // SkRefPtr and new both took a reference. insert("CA", alpha.get()); insert("ca", alpha.get()); SK_COMPILE_ASSERT(SkPaint::kButt_Cap == 0, paint_cap_mismatch); SK_COMPILE_ASSERT(SkPaint::kRound_Cap == 1, paint_cap_mismatch); SK_COMPILE_ASSERT(SkPaint::kSquare_Cap == 2, paint_cap_mismatch); SK_COMPILE_ASSERT(SkPaint::kCapCount == 3, paint_cap_mismatch); SkASSERT(fPaint.getStrokeCap() >= 0 && fPaint.getStrokeCap() <= 2); insertInt("LC", fPaint.getStrokeCap()); SK_COMPILE_ASSERT(SkPaint::kMiter_Join == 0, paint_join_mismatch); SK_COMPILE_ASSERT(SkPaint::kRound_Join == 1, paint_join_mismatch); SK_COMPILE_ASSERT(SkPaint::kBevel_Join == 2, paint_join_mismatch); SK_COMPILE_ASSERT(SkPaint::kJoinCount == 3, paint_join_mismatch); SkASSERT(fPaint.getStrokeJoin() >= 0 && fPaint.getStrokeJoin() <= 2); insertInt("LJ", fPaint.getStrokeJoin()); insertScalar("LW", fPaint.getStrokeWidth()); insertScalar("ML", fPaint.getStrokeMiter()); insert("SA", new SkPDFBool(true))->unref(); // Auto stroke adjustment. SkXfermode::Mode xfermode = SkXfermode::kSrcOver_Mode; // If asMode fails, default to kSrcOver_Mode. if (fPaint.getXfermode()) fPaint.getXfermode()->asMode(&xfermode); // If we don't support the mode, just use kSrcOver_Mode. if (xfermode < 0 || xfermode > SkXfermode::kLastMode || blend_mode_from_xfermode(xfermode) == NULL) { xfermode = SkXfermode::kSrcOver_Mode; NOT_IMPLEMENTED("unsupported xfermode", false); } insertName("BM", blend_mode_from_xfermode(xfermode)); } }
SkMutex::SkMutex() { SK_COMPILE_ASSERT(sizeof(fStorage) > sizeof(CRITICAL_SECTION), NotEnoughSizeForCriticalSection); InitializeCriticalSection(reinterpret_cast<CRITICAL_SECTION*>(&fStorage)); }
void SkPDFDevice::updateGSFromPaint(const SkPaint& paint, bool forText) { SkASSERT(paint.getPathEffect() == NULL); NOT_IMPLEMENTED(paint.getMaskFilter() != NULL, false); NOT_IMPLEMENTED(paint.getColorFilter() != NULL, false); SkPaint newPaint = paint; // PDF treats a shader as a color, so we only set one or the other. SkRefPtr<SkPDFShader> pdfShader; const SkShader* shader = newPaint.getShader(); if (shader) { // PDF positions patterns relative to the initial transform, so // we need to apply the current transform to the shader parameters. SkMatrix transform = fGraphicStack[fGraphicStackIndex].fTransform; if (fFlipOrigin == kFlip_OriginTransform) { transform.postScale(1, -1); transform.postTranslate(0, fHeight); } // PDF doesn't support kClamp_TileMode, so we simulate it by making // a pattern the size of the drawing service. SkIRect bounds = fGraphicStack[fGraphicStackIndex].fClip.getBounds(); pdfShader = SkPDFShader::getPDFShader(*shader, transform, bounds); SkSafeUnref(pdfShader.get()); // getShader and SkRefPtr both took a ref // A color shader is treated as an invalid shader so we don't have // to set a shader just for a color. if (pdfShader.get() == NULL) { newPaint.setColor(0); // Check for a color shader. SkShader::GradientInfo gradientInfo; SkColor gradientColor; gradientInfo.fColors = &gradientColor; gradientInfo.fColorOffsets = NULL; gradientInfo.fColorCount = 1; if (shader->asAGradient(&gradientInfo) == SkShader::kColor_GradientType) { newPaint.setColor(gradientColor); } } } if (pdfShader) { // pdfShader has been canonicalized so we can directly compare // pointers. if (fGraphicStack[fGraphicStackIndex].fShader != pdfShader.get()) { int resourceIndex = fShaderResources.find(pdfShader.get()); if (resourceIndex < 0) { resourceIndex = fShaderResources.count(); fShaderResources.push(pdfShader.get()); pdfShader->ref(); } fContent.writeText("/Pattern CS /Pattern cs /P"); fContent.writeDecAsText(resourceIndex); fContent.writeText(" SCN /P"); fContent.writeDecAsText(resourceIndex); fContent.writeText(" scn\n"); fGraphicStack[fGraphicStackIndex].fShader = pdfShader.get(); } } else { SkColor newColor = newPaint.getColor(); newColor = SkColorSetA(newColor, 0xFF); if (fGraphicStack[fGraphicStackIndex].fShader || fGraphicStack[fGraphicStackIndex].fColor != newColor) { emitPDFColor(newColor, &fContent); fContent.writeText("RG "); emitPDFColor(newColor, &fContent); fContent.writeText("rg\n"); fGraphicStack[fGraphicStackIndex].fColor = newColor; fGraphicStack[fGraphicStackIndex].fShader = NULL; } } SkRefPtr<SkPDFGraphicState> newGraphicState = SkPDFGraphicState::getGraphicStateForPaint(newPaint); newGraphicState->unref(); // getGraphicState and SkRefPtr both took a ref. // newGraphicState has been canonicalized so we can directly compare // pointers. if (fGraphicStack[fGraphicStackIndex].fGraphicState != newGraphicState.get()) { int resourceIndex = fGraphicStateResources.find(newGraphicState.get()); if (resourceIndex < 0) { resourceIndex = fGraphicStateResources.count(); fGraphicStateResources.push(newGraphicState.get()); newGraphicState->ref(); } fContent.writeText("/G"); fContent.writeDecAsText(resourceIndex); fContent.writeText(" gs\n"); fGraphicStack[fGraphicStackIndex].fGraphicState = newGraphicState.get(); } if (forText) { if (fGraphicStack[fGraphicStackIndex].fTextScaleX != newPaint.getTextScaleX()) { SkScalar scale = newPaint.getTextScaleX(); SkScalar pdfScale = SkScalarMul(scale, SkIntToScalar(100)); SkPDFScalar::Append(pdfScale, &fContent); fContent.writeText(" Tz\n"); fGraphicStack[fGraphicStackIndex].fTextScaleX = scale; } if (fGraphicStack[fGraphicStackIndex].fTextFill != newPaint.getStyle()) { SK_COMPILE_ASSERT(SkPaint::kFill_Style == 0, enum_must_match_value); SK_COMPILE_ASSERT(SkPaint::kStroke_Style == 1, enum_must_match_value); SK_COMPILE_ASSERT(SkPaint::kStrokeAndFill_Style == 2, enum_must_match_value); fContent.writeDecAsText(newPaint.getStyle()); fContent.writeText(" Tr\n"); fGraphicStack[fGraphicStackIndex].fTextFill = newPaint.getStyle(); } } }
// Return the offset of the paint inside a given op's byte stream. A zero // return value means there is no paint (and you really shouldn't be calling // this method) static inline size_t get_paint_offset(DrawType op, size_t opSize) { // These offsets are where the paint would be if the op size doesn't overflow static const uint8_t gPaintOffsets[] = { 0, // UNUSED - no paint 0, // CLIP_PATH - no paint 0, // CLIP_REGION - no paint 0, // CLIP_RECT - no paint 0, // CLIP_RRECT - no paint 0, // CONCAT - no paint 1, // DRAW_BITMAP - right after op code 1, // DRAW_BITMAP_MATRIX - right after op code, deprecated 1, // DRAW_BITMAP_NINE - right after op code 1, // DRAW_BITMAP_RECT_TO_RECT - right after op code 0, // DRAW_CLEAR - no paint 0, // DRAW_DATA - no paint 1, // DRAW_OVAL - right after op code 1, // DRAW_PAINT - right after op code 1, // DRAW_PATH - right after op code 0, // DRAW_PICTURE - no paint 1, // DRAW_POINTS - right after op code 1, // DRAW_POS_TEXT - right after op code 1, // DRAW_POS_TEXT_TOP_BOTTOM - right after op code 1, // DRAW_POS_TEXT_H - right after op code 1, // DRAW_POS_TEXT_H_TOP_BOTTOM - right after op code 1, // DRAW_RECT - right after op code 1, // DRAW_RRECT - right after op code 1, // DRAW_SPRITE - right after op code 1, // DRAW_TEXT - right after op code 1, // DRAW_TEXT_ON_PATH - right after op code 1, // DRAW_TEXT_TOP_BOTTOM - right after op code 1, // DRAW_VERTICES - right after op code 0, // RESTORE - no paint 0, // ROTATE - no paint 0, // SAVE - no paint 0, // SAVE_LAYER - see below - this paint's location varies 0, // SCALE - no paint 0, // SET_MATRIX - no paint 0, // SKEW - no paint 0, // TRANSLATE - no paint 0, // NOOP - no paint 0, // BEGIN_GROUP - no paint 0, // COMMENT - no paint 0, // END_GROUP - no paint 1, // DRAWDRRECT - right after op code 0, // PUSH_CULL - no paint 0, // POP_CULL - no paint 1, // DRAW_PATCH - right after op code 1, // DRAW_PICTURE_MATRIX_PAINT - right after op code 1, // DRAW_TEXT_BLOB- right after op code }; SK_COMPILE_ASSERT(sizeof(gPaintOffsets) == LAST_DRAWTYPE_ENUM + 1, need_to_be_in_sync); SkASSERT((unsigned)op <= (unsigned)LAST_DRAWTYPE_ENUM); int overflow = 0; if (0 != (opSize & ~MASK_24) || opSize == MASK_24) { // This op's size overflows so an extra uint32_t will be written // after the op code overflow = sizeof(uint32_t); } if (SAVE_LAYER == op) { static const uint32_t kSaveLayerNoBoundsPaintOffset = 2 * kUInt32Size; static const uint32_t kSaveLayerWithBoundsPaintOffset = 2 * kUInt32Size + sizeof(SkRect); if (kSaveLayerNoBoundsSize == opSize) { return kSaveLayerNoBoundsPaintOffset + overflow; } else { SkASSERT(kSaveLayerWithBoundsSize == opSize); return kSaveLayerWithBoundsPaintOffset + overflow; } } SkASSERT(0 != gPaintOffsets[op]); // really shouldn't be calling this method return gPaintOffsets[op] * sizeof(uint32_t) + overflow; }
void GrGLPath::InitPathObject(GrGLGpu* gpu, GrGLuint pathID, const SkPath& skPath, const GrStrokeInfo& stroke) { SkASSERT(!stroke.isDashed()); if (!skPath.isEmpty()) { int verbCnt = skPath.countVerbs(); int pointCnt = skPath.countPoints(); int minCoordCnt = pointCnt * 2; SkSTArray<16, GrGLubyte, true> pathCommands(verbCnt); SkSTArray<16, GrGLfloat, true> pathCoords(minCoordCnt); SkDEBUGCODE(int numCoords = 0); if ((skPath.getSegmentMasks() & SkPath::kConic_SegmentMask) == 0) { // This branch does type punning, converting SkPoint* to GrGLfloat*. SK_COMPILE_ASSERT(sizeof(SkPoint) == sizeof(GrGLfloat) * 2, sk_point_not_two_floats); // This branch does not convert with SkScalarToFloat. #ifndef SK_SCALAR_IS_FLOAT #error Need SK_SCALAR_IS_FLOAT. #endif pathCommands.resize_back(verbCnt); pathCoords.resize_back(minCoordCnt); skPath.getPoints(reinterpret_cast<SkPoint*>(&pathCoords[0]), pointCnt); skPath.getVerbs(&pathCommands[0], verbCnt); for (int i = 0; i < verbCnt; ++i) { SkPath::Verb v = static_cast<SkPath::Verb>(pathCommands[i]); pathCommands[i] = verb_to_gl_path_cmd(v); SkDEBUGCODE(numCoords += num_coords(v)); } } else { SkPoint points[4]; SkPath::RawIter iter(skPath); SkPath::Verb verb; while ((verb = iter.next(points)) != SkPath::kDone_Verb) { pathCommands.push_back(verb_to_gl_path_cmd(verb)); GrGLfloat coords[6]; int coordsForVerb; switch (verb) { case SkPath::kMove_Verb: points_to_coords(points, 0, 1, coords); coordsForVerb = 2; break; case SkPath::kLine_Verb: points_to_coords(points, 1, 1, coords); coordsForVerb = 2; break; case SkPath::kConic_Verb: points_to_coords(points, 1, 2, coords); coords[4] = SkScalarToFloat(iter.conicWeight()); coordsForVerb = 5; break; case SkPath::kQuad_Verb: points_to_coords(points, 1, 2, coords); coordsForVerb = 4; break; case SkPath::kCubic_Verb: points_to_coords(points, 1, 3, coords); coordsForVerb = 6; break; case SkPath::kClose_Verb: continue; default: SkASSERT(false); // Not reached. continue; } SkDEBUGCODE(numCoords += num_coords(verb)); pathCoords.push_back_n(coordsForVerb, coords); } } SkASSERT(verbCnt == pathCommands.count()); SkASSERT(numCoords == pathCoords.count()); GR_GL_CALL(gpu->glInterface(), PathCommands(pathID, pathCommands.count(), &pathCommands[0], pathCoords.count(), GR_GL_FLOAT, &pathCoords[0])); } else { GR_GL_CALL(gpu->glInterface(), PathCommands(pathID, 0, NULL, 0, GR_GL_FLOAT, NULL)); } if (stroke.needToApply()) { SkASSERT(!stroke.isHairlineStyle()); GR_GL_CALL(gpu->glInterface(), PathParameterf(pathID, GR_GL_PATH_STROKE_WIDTH, SkScalarToFloat(stroke.getWidth()))); GR_GL_CALL(gpu->glInterface(), PathParameterf(pathID, GR_GL_PATH_MITER_LIMIT, SkScalarToFloat(stroke.getMiter()))); GrGLenum join = join_to_gl_join(stroke.getJoin()); GR_GL_CALL(gpu->glInterface(), PathParameteri(pathID, GR_GL_PATH_JOIN_STYLE, join)); GrGLenum cap = cap_to_gl_cap(stroke.getCap()); GR_GL_CALL(gpu->glInterface(), PathParameteri(pathID, GR_GL_PATH_END_CAPS, cap)); GR_GL_CALL(gpu->glInterface(), PathParameterf(pathID, GR_GL_PATH_STROKE_BOUND, 0.02f)); } }
static jlong CreateXfermode(JNIEnv* env, jobject, jint modeHandle) { // validate that the Java enum values match our expectations SK_COMPILE_ASSERT(0 == SkXfermode::kClear_Mode, xfermode_mismatch); SK_COMPILE_ASSERT(1 == SkXfermode::kSrc_Mode, xfermode_mismatch); SK_COMPILE_ASSERT(2 == SkXfermode::kDst_Mode, xfermode_mismatch); SK_COMPILE_ASSERT(3 == SkXfermode::kSrcOver_Mode, xfermode_mismatch); SK_COMPILE_ASSERT(4 == SkXfermode::kDstOver_Mode, xfermode_mismatch); SK_COMPILE_ASSERT(5 == SkXfermode::kSrcIn_Mode, xfermode_mismatch); SK_COMPILE_ASSERT(6 == SkXfermode::kDstIn_Mode, xfermode_mismatch); SK_COMPILE_ASSERT(7 == SkXfermode::kSrcOut_Mode, xfermode_mismatch); SK_COMPILE_ASSERT(8 == SkXfermode::kDstOut_Mode, xfermode_mismatch); SK_COMPILE_ASSERT(9 == SkXfermode::kSrcATop_Mode, xfermode_mismatch); SK_COMPILE_ASSERT(10 == SkXfermode::kDstATop_Mode, xfermode_mismatch); SK_COMPILE_ASSERT(11 == SkXfermode::kXor_Mode, xfermode_mismatch); SK_COMPILE_ASSERT(16 == SkXfermode::kDarken_Mode, xfermode_mismatch); SK_COMPILE_ASSERT(17 == SkXfermode::kLighten_Mode, xfermode_mismatch); SK_COMPILE_ASSERT(13 == SkXfermode::kModulate_Mode, xfermode_mismatch); SK_COMPILE_ASSERT(14 == SkXfermode::kScreen_Mode, xfermode_mismatch); SK_COMPILE_ASSERT(12 == SkXfermode::kPlus_Mode, xfermode_mismatch); SK_COMPILE_ASSERT(15 == SkXfermode::kOverlay_Mode, xfermode_mismatch); SkXfermode::Mode mode = static_cast<SkXfermode::Mode>(modeHandle); return reinterpret_cast<jlong>(SkXfermode::Create(mode)); }
void onOnceBeforeDraw() override { fPaint.setAntiAlias(true); fPaint.setLCDRenderText(fLCD); SkISize size = this->getISize(); SkScalar w = SkIntToScalar(size.fWidth); SkScalar h = SkIntToScalar(size.fHeight); SK_COMPILE_ASSERT(4 == SK_ARRAY_COUNT(fTypefacesToUnref), typeface_cnt); fTypefacesToUnref[0] = sk_tool_utils::create_portable_typeface("sans-serif", SkTypeface::kNormal); fTypefacesToUnref[1] = sk_tool_utils::create_portable_typeface("sans-serif", SkTypeface::kBold); fTypefacesToUnref[2] = sk_tool_utils::create_portable_typeface("serif", SkTypeface::kNormal); fTypefacesToUnref[3] = sk_tool_utils::create_portable_typeface("serif", SkTypeface::kBold); SkRandom random; for (int i = 0; i < kCnt; ++i) { int length = random.nextRangeU(kMinLength, kMaxLength); char text[kMaxLength]; for (int j = 0; j < length; ++j) { text[j] = (char)random.nextRangeU('!', 'z'); } fStrings[i].set(text, length); fColors[i] = random.nextU(); fColors[i] |= 0xFF000000; fColors[i] = sk_tool_utils::color_to_565(fColors[i]); static const SkScalar kMinPtSize = 8.f; static const SkScalar kMaxPtSize = 32.f; fPtSizes[i] = random.nextRangeScalar(kMinPtSize, kMaxPtSize); fTypefaces[i] = fTypefacesToUnref[ random.nextULessThan(SK_ARRAY_COUNT(fTypefacesToUnref))]; SkRect r; fPaint.setColor(fColors[i]); fPaint.setTypeface(fTypefaces[i]); fPaint.setTextSize(fPtSizes[i]); fPaint.measureText(fStrings[i].c_str(), fStrings[i].size(), &r); // safeRect is set of x,y positions where we can draw the string without hitting // the GM's border. SkRect safeRect = SkRect::MakeLTRB(-r.fLeft, -r.fTop, w - r.fRight, h - r.fBottom); if (safeRect.isEmpty()) { // If we don't fit then just don't worry about how we get cliped to the device // border. safeRect = SkRect::MakeWH(w, h); } fPositions[i].fX = random.nextRangeScalar(safeRect.fLeft, safeRect.fRight); fPositions[i].fY = random.nextRangeScalar(safeRect.fTop, safeRect.fBottom); fClipRects[i] = r; fClipRects[i].offset(fPositions[i].fX, fPositions[i].fY); fClipRects[i].outset(2.f, 2.f); if (fEffectiveClip) { fClipRects[i].fRight -= 0.25f * fClipRects[i].width(); } } }