void onDraw(SkCanvas* canvas) override { SkPaint paint; paint.setImageFilter(SkBlurImageFilter::Create(fSigmaX, fSigmaY))->unref(); canvas->saveLayer(NULL, &paint); const char* str = "The quick brown fox jumped over the lazy dog."; SkRandom rand; SkPaint textPaint; textPaint.setAntiAlias(true); sk_tool_utils::set_portable_typeface_always(&textPaint); for (int i = 0; i < 25; ++i) { int x = rand.nextULessThan(WIDTH); int y = rand.nextULessThan(HEIGHT); textPaint.setColor(sk_tool_utils::color_to_565(rand.nextBits(24) | 0xFF000000)); textPaint.setTextSize(rand.nextRangeScalar(0, 300)); canvas->drawText(str, strlen(str), SkIntToScalar(x), SkIntToScalar(y), textPaint); } canvas->restore(); }
void makePath(SkPath* path) override { SkRandom rand; int size = SK_ARRAY_COUNT(points); int hSize = size / 2; for (int i = 0; i < kMaxPathSize; ++i) { int xTrans = 10 + 40 * (i%(kMaxPathSize/2)); int yTrans = 0; if (i > kMaxPathSize/2 - 1) { yTrans = 40; } int base1 = 2 * rand.nextULessThan(hSize); int base2 = 2 * rand.nextULessThan(hSize); int base3 = 2 * rand.nextULessThan(hSize); path->moveTo(SkIntToScalar(points[base1] + xTrans), SkIntToScalar(points[base1+1] + yTrans)); path->lineTo(SkIntToScalar(points[base2] + xTrans), SkIntToScalar(points[base2+1] + yTrans)); path->lineTo(SkIntToScalar(points[base3] + xTrans), SkIntToScalar(points[base3+1] + yTrans)); } }
DEF_SIMPLE_GM_BG(imagemagnifier, canvas, WIDTH, HEIGHT, SK_ColorBLACK) { SkPaint filterPaint; filterPaint.setImageFilter( SkMagnifierImageFilter::Make( SkRect::MakeXYWH(SkIntToScalar(100), SkIntToScalar(100), SkIntToScalar(WIDTH / 2), SkIntToScalar(HEIGHT / 2)), 100, nullptr)); canvas->saveLayer(nullptr, &filterPaint); const char* str = "The quick brown fox jumped over the lazy dog."; SkRandom rand; for (int i = 0; i < 25; ++i) { int x = rand.nextULessThan(WIDTH); int y = rand.nextULessThan(HEIGHT); SkPaint paint; sk_tool_utils::set_portable_typeface(&paint); paint.setColor(sk_tool_utils::color_to_565(rand.nextBits(24) | 0xFF000000)); paint.setTextSize(rand.nextRangeScalar(0, 300)); paint.setAntiAlias(true); canvas->drawText(str, strlen(str), SkIntToScalar(x), SkIntToScalar(y), paint); } canvas->restore(); }
void onDraw(SkCanvas* canvas) override { SkPaint filterPaint; filterPaint.setImageFilter( SkMagnifierImageFilter::Create( SkRect::MakeXYWH(SkIntToScalar(100), SkIntToScalar(100), SkIntToScalar(WIDTH / 2), SkIntToScalar(HEIGHT / 2)), 100))->unref(); canvas->saveLayer(NULL, &filterPaint); const char* str = "The quick brown fox jumped over the lazy dog."; SkRandom rand; for (int i = 0; i < 25; ++i) { int x = rand.nextULessThan(WIDTH); int y = rand.nextULessThan(HEIGHT); SkPaint paint; sk_tool_utils::set_portable_typeface(&paint); paint.setColor(sk_tool_utils::color_to_565(rand.nextBits(24) | 0xFF000000)); paint.setTextSize(rand.nextRangeScalar(0, 300)); paint.setAntiAlias(true); canvas->drawText(str, strlen(str), SkIntToScalar(x), SkIntToScalar(y), paint); } canvas->restore(); }
template <typename Array> static void test_array_reserve(skiatest::Reporter* reporter, Array* array, int reserveCount) { SkRandom random; REPORTER_ASSERT(reporter, array->allocCntForTest() >= reserveCount); array->push_back(); REPORTER_ASSERT(reporter, array->allocCntForTest() >= reserveCount); array->pop_back(); REPORTER_ASSERT(reporter, array->allocCntForTest() >= reserveCount); while (array->count() < reserveCount) { // Two steps forward, one step back if (random.nextULessThan(3) < 2) { array->push_back(); } else if (array->count() > 0) { array->pop_back(); } REPORTER_ASSERT(reporter, array->allocCntForTest() >= reserveCount); } }
static void test_empty_back_and_pop(skiatest::Reporter* reporter) { SkRandom rand; for (int data = 0; data < 2; ++data) { // Do this with different starting sizes to have different alignment between blocks and pops. // pops. We want to test poping the first guy off, guys in the middle of the block, and the // first guy on a non-head block. for (int j = 0; j < 8; ++j) { GrTRecorder<IntWrapper, int> recorder(j); REPORTER_ASSERT(reporter, recorder.empty()); for (int i = 0; i < 100; ++i) { if (data) { REPORTER_ASSERT(reporter, i == *GrNEW_APPEND_TO_RECORDER(recorder, IntWrapper, (i))); } else { REPORTER_ASSERT(reporter, i == *GrNEW_APPEND_WITH_DATA_TO_RECORDER(recorder, IntWrapper, (i), rand.nextULessThan(10))); } REPORTER_ASSERT(reporter, !recorder.empty()); REPORTER_ASSERT(reporter, i == recorder.back()); if (0 == (i % 7)) { recorder.pop_back(); if (i > 0) { REPORTER_ASSERT(reporter, !recorder.empty()); REPORTER_ASSERT(reporter, i-1 == recorder.back()); } } } REPORTER_ASSERT(reporter, !recorder.empty()); recorder.reset(); REPORTER_ASSERT(reporter, recorder.empty()); } } }
static void TestTLList(skiatest::Reporter* reporter) { typedef SkTLList<ListElement> ElList; typedef ElList::Iter Iter; SkRandom random; for (int i = 1; i <= 16; i *= 2) { ElList list1(i); ElList list2(i); Iter iter1; Iter iter2; Iter iter3; Iter iter4; #if SK_ENABLE_INST_COUNT SkASSERT(0 == ListElement::InstanceCount()); #endif REPORTER_ASSERT(reporter, list1.isEmpty()); REPORTER_ASSERT(reporter, NULL == iter1.init(list1, Iter::kHead_IterStart)); REPORTER_ASSERT(reporter, NULL == iter1.init(list1, Iter::kTail_IterStart)); // Try popping an empty list list1.popHead(); list1.popTail(); REPORTER_ASSERT(reporter, list1.isEmpty()); REPORTER_ASSERT(reporter, list1 == list2); // Create two identical lists, one by appending to head and the other to the tail. list1.addToHead(ListElement(1)); list2.addToTail(ListElement(1)); #if SK_ENABLE_INST_COUNT SkASSERT(2 == ListElement::InstanceCount()); #endif iter1.init(list1, Iter::kHead_IterStart); iter2.init(list1, Iter::kTail_IterStart); REPORTER_ASSERT(reporter, iter1.get()->fID == iter2.get()->fID); iter3.init(list2, Iter::kHead_IterStart); iter4.init(list2, Iter::kTail_IterStart); REPORTER_ASSERT(reporter, iter3.get()->fID == iter1.get()->fID); REPORTER_ASSERT(reporter, iter4.get()->fID == iter1.get()->fID); REPORTER_ASSERT(reporter, list1 == list2); list2.reset(); // use both before/after in-place construction on an empty list SkNEW_INSERT_IN_LLIST_BEFORE(&list2, list2.headIter(), ListElement, (1)); REPORTER_ASSERT(reporter, list2 == list1); list2.reset(); SkNEW_INSERT_IN_LLIST_AFTER(&list2, list2.tailIter(), ListElement, (1)); REPORTER_ASSERT(reporter, list2 == list1); // add an element to the second list, check that iters are still valid iter3.init(list2, Iter::kHead_IterStart); iter4.init(list2, Iter::kTail_IterStart); list2.addToHead(ListElement(2)); #if SK_ENABLE_INST_COUNT SkASSERT(3 == ListElement::InstanceCount()); #endif REPORTER_ASSERT(reporter, iter3.get()->fID == iter1.get()->fID); REPORTER_ASSERT(reporter, iter4.get()->fID == iter1.get()->fID); REPORTER_ASSERT(reporter, 1 == Iter(list2, Iter::kTail_IterStart).get()->fID); REPORTER_ASSERT(reporter, 2 == Iter(list2, Iter::kHead_IterStart).get()->fID); REPORTER_ASSERT(reporter, list1 != list2); list1.addToHead(ListElement(2)); REPORTER_ASSERT(reporter, list1 == list2); #if SK_ENABLE_INST_COUNT SkASSERT(4 == ListElement::InstanceCount()); #endif REPORTER_ASSERT(reporter, !list1.isEmpty()); list1.reset(); list2.reset(); #if SK_ENABLE_INST_COUNT SkASSERT(0 == ListElement::InstanceCount()); #endif REPORTER_ASSERT(reporter, list1.isEmpty() && list2.isEmpty()); // randomly perform insertions and deletions on a list and perform tests int count = 0; for (int j = 0; j < 100; ++j) { if (list1.isEmpty() || random.nextBiasedBool(3 * SK_Scalar1 / 4)) { int id = j; // Choose one of three ways to insert a new element: at the head, at the tail, // before a random element, after a random element int numValidMethods = 0 == count ? 2 : 4; int insertionMethod = random.nextULessThan(numValidMethods); switch (insertionMethod) { case 0: list1.addToHead(ListElement(id)); break; case 1: list1.addToTail(ListElement(id)); break; case 2: // fallthru to share code that picks random element. case 3: { int n = random.nextULessThan(list1.count()); Iter iter = list1.headIter(); // remember the elements before/after the insertion point. while (n--) { iter.next(); } Iter prev(iter); Iter next(iter); next.next(); prev.prev(); SkASSERT(NULL != iter.get()); // insert either before or after the iterator, then check that the // surrounding sequence is correct. if (2 == insertionMethod) { SkNEW_INSERT_IN_LLIST_BEFORE(&list1, iter, ListElement, (id)); Iter newItem(iter); newItem.prev(); REPORTER_ASSERT(reporter, newItem.get()->fID == id); if (NULL != next.get()) { REPORTER_ASSERT(reporter, next.prev()->fID == iter.get()->fID); } if (NULL != prev.get()) { REPORTER_ASSERT(reporter, prev.next()->fID == id); } } else { SkNEW_INSERT_IN_LLIST_AFTER(&list1, iter, ListElement, (id)); Iter newItem(iter); newItem.next(); REPORTER_ASSERT(reporter, newItem.get()->fID == id); if (NULL != next.get()) { REPORTER_ASSERT(reporter, next.prev()->fID == id); } if (NULL != prev.get()) { REPORTER_ASSERT(reporter, prev.next()->fID == iter.get()->fID); } } } } ++count; } else { // walk to a random place either forward or backwards and remove. int n = random.nextULessThan(list1.count()); Iter::IterStart start; ListElement* (Iter::*incrFunc)(); if (random.nextBool()) { start = Iter::kHead_IterStart; incrFunc = &Iter::next; } else { start = Iter::kTail_IterStart; incrFunc = &Iter::prev; } // find the element Iter iter(list1, start); while (n--) { REPORTER_ASSERT(reporter, NULL != iter.get()); (iter.*incrFunc)(); } REPORTER_ASSERT(reporter, NULL != iter.get()); // remember the prev and next elements from the element to be removed Iter prev = iter; Iter next = iter; prev.prev(); next.next(); list1.remove(iter.get()); // make sure the remembered next/prev iters still work Iter pn = prev; pn.next(); Iter np = next; np.prev(); // pn should match next unless the target node was the head, in which case prev // walked off the list. REPORTER_ASSERT(reporter, pn.get() == next.get() || NULL == prev.get()); // Similarly, np should match prev unless next originally walked off the tail. REPORTER_ASSERT(reporter, np.get() == prev.get() || NULL == next.get()); --count; } REPORTER_ASSERT(reporter, count == list1.count()); #if SK_ENABLE_INST_COUNT SkASSERT(count == ListElement::InstanceCount()); #endif } list1.reset(); #if SK_ENABLE_INST_COUNT SkASSERT(0 == ListElement::InstanceCount()); #endif } }
bool GrGpuGL::programUnitTest(int maxStages) { GrTextureDesc dummyDesc; dummyDesc.fFlags = kRenderTarget_GrTextureFlagBit; dummyDesc.fConfig = kSkia8888_GrPixelConfig; dummyDesc.fWidth = 34; dummyDesc.fHeight = 18; SkAutoTUnref<GrTexture> dummyTexture1(this->createTexture(dummyDesc, NULL, 0)); dummyDesc.fFlags = kNone_GrTextureFlags; dummyDesc.fConfig = kAlpha_8_GrPixelConfig; dummyDesc.fWidth = 16; dummyDesc.fHeight = 22; SkAutoTUnref<GrTexture> dummyTexture2(this->createTexture(dummyDesc, NULL, 0)); if (!dummyTexture1 || ! dummyTexture2) { return false; } static const int NUM_TESTS = 512; SkRandom random; for (int t = 0; t < NUM_TESTS; ++t) { #if 0 GrPrintf("\nTest Program %d\n-------------\n", t); static const int stop = -1; if (t == stop) { int breakpointhere = 9; } #endif GrGLProgramDesc pdesc; int currAttribIndex = 1; // we need to always leave room for position int currTextureCoordSet = 0; GrTexture* dummyTextures[] = {dummyTexture1.get(), dummyTexture2.get()}; int numStages = random.nextULessThan(maxStages + 1); int numColorStages = random.nextULessThan(numStages + 1); int numCoverageStages = numStages - numColorStages; SkAutoSTMalloc<8, const GrFragmentStage*> stages(numStages); bool usePathRendering = this->glCaps().pathRenderingSupport() && random.nextBool(); GrGpu::DrawType drawType = usePathRendering ? GrGpu::kDrawPath_DrawType : GrGpu::kDrawPoints_DrawType; SkAutoTDelete<GrGeometryStage> geometryProcessor; bool hasGeometryProcessor = usePathRendering ? false : random.nextBool(); if (hasGeometryProcessor) { while (true) { SkAutoTUnref<const GrGeometryProcessor> effect( GrProcessorTestFactory<GrGeometryProcessor>::CreateStage(&random, this->getContext(), *this->caps(), dummyTextures)); SkASSERT(effect); // Only geometryProcessor can use vertex shader GrGeometryStage* stage = SkNEW_ARGS(GrGeometryStage, (effect.get())); geometryProcessor.reset(stage); // we have to set dummy vertex attribs const GrGeometryProcessor::VertexAttribArray& v = effect->getVertexAttribs(); int numVertexAttribs = v.count(); SkASSERT(GrGeometryProcessor::kMaxVertexAttribs == 2 && GrGeometryProcessor::kMaxVertexAttribs >= numVertexAttribs); size_t runningStride = GrVertexAttribTypeSize(genericVertexAttribs[0].fType); for (int i = 0; i < numVertexAttribs; i++) { genericVertexAttribs[i + 1].fOffset = runningStride; genericVertexAttribs[i + 1].fType = convert_sltype_to_attribtype(v[i].getType()); runningStride += GrVertexAttribTypeSize(genericVertexAttribs[i + 1].fType); } // update the vertex attributes with the ds GrDrawState* ds = this->drawState(); ds->setVertexAttribs<genericVertexAttribs>(numVertexAttribs + 1, runningStride); currAttribIndex = numVertexAttribs + 1; break; } } for (int s = 0; s < numStages;) { SkAutoTUnref<const GrFragmentProcessor> effect( GrProcessorTestFactory<GrFragmentProcessor>::CreateStage( &random, this->getContext(), *this->caps(), dummyTextures)); SkASSERT(effect); // If adding this effect would exceed the max texture coord set count then generate a // new random effect. if (usePathRendering && this->glPathRendering()->texturingMode() == GrGLPathRendering::FixedFunction_TexturingMode) {; int numTransforms = effect->numTransforms(); if (currTextureCoordSet + numTransforms > this->glCaps().maxFixedFunctionTextureCoords()) { continue; } currTextureCoordSet += numTransforms; } GrFragmentStage* stage = SkNEW_ARGS(GrFragmentStage, (effect.get())); stages[s] = stage; ++s; } const GrTexture* dstTexture = random.nextBool() ? dummyTextures[0] : dummyTextures[1]; if (!pdesc.setRandom(&random, this, dummyTextures[0]->asRenderTarget(), dstTexture, geometryProcessor.get(), stages.get(), numColorStages, numCoverageStages, currAttribIndex, drawType)) { return false; } SkAutoTUnref<GrOptDrawState> optState(GrOptDrawState::Create(this->getDrawState(), *this->caps(), drawType)); SkAutoTUnref<GrGLProgram> program( GrGLProgramBuilder::CreateProgram(*optState, pdesc, drawType, geometryProcessor, stages, stages + numColorStages, this)); for (int s = 0; s < numStages; ++s) { SkDELETE(stages[s]); } if (NULL == program.get()) { return false; } // We have to reset the drawstate because we might have added a gp this->drawState()->reset(); } return true; }
void onOnceBeforeDraw() override { fPaint.setAntiAlias(true); fPaint.setLCDRenderText(fLCD); SkISize size = this->getISize(); SkScalar w = SkIntToScalar(size.fWidth); SkScalar h = SkIntToScalar(size.fHeight); static_assert(4 == SK_ARRAY_COUNT(fTypefaces), "typeface_cnt"); fTypefaces[0] = sk_tool_utils::create_portable_typeface("sans-serif", SkFontStyle()); fTypefaces[1] = sk_tool_utils::create_portable_typeface("sans-serif", SkFontStyle::FromOldStyle(SkTypeface::kBold)); fTypefaces[2] = sk_tool_utils::create_portable_typeface("serif", SkFontStyle()); fTypefaces[3] = sk_tool_utils::create_portable_typeface("serif", SkFontStyle::FromOldStyle(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); fTypefaceIndices[i] = random.nextULessThan(SK_ARRAY_COUNT(fTypefaces)); SkRect r; fPaint.setColor(fColors[i]); fPaint.setTypeface(fTypefaces[fTypefaceIndices[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(); } } }
bool GrGpuGL::programUnitTest(int maxStages) { GrTextureDesc dummyDesc; dummyDesc.fFlags = kRenderTarget_GrTextureFlagBit; dummyDesc.fConfig = kSkia8888_GrPixelConfig; dummyDesc.fWidth = 34; dummyDesc.fHeight = 18; SkAutoTUnref<GrTexture> dummyTexture1(this->createTexture(dummyDesc, NULL, 0)); dummyDesc.fFlags = kNone_GrTextureFlags; dummyDesc.fConfig = kAlpha_8_GrPixelConfig; dummyDesc.fWidth = 16; dummyDesc.fHeight = 22; SkAutoTUnref<GrTexture> dummyTexture2(this->createTexture(dummyDesc, NULL, 0)); static const int NUM_TESTS = 512; SkRandom random; for (int t = 0; t < NUM_TESTS; ++t) { #if 0 GrPrintf("\nTest Program %d\n-------------\n", t); static const int stop = -1; if (t == stop) { int breakpointhere = 9; } #endif GrGLProgramDesc pdesc; int currAttribIndex = 1; // we need to always leave room for position int currTextureCoordSet = 0; int attribIndices[2] = { 0, 0 }; GrTexture* dummyTextures[] = {dummyTexture1.get(), dummyTexture2.get()}; int numStages = random.nextULessThan(maxStages + 1); int numColorStages = random.nextULessThan(numStages + 1); int numCoverageStages = numStages - numColorStages; SkAutoSTMalloc<8, const GrEffectStage*> stages(numStages); bool useFixedFunctionTexturing = this->shouldUseFixedFunctionTexturing(); for (int s = 0; s < numStages;) { SkAutoTUnref<const GrEffectRef> effect(GrEffectTestFactory::CreateStage( &random, this->getContext(), *this->caps(), dummyTextures)); SkASSERT(effect); int numAttribs = (*effect)->numVertexAttribs(); // If adding this effect would exceed the max attrib count then generate a // new random effect. if (currAttribIndex + numAttribs > GrDrawState::kMaxVertexAttribCnt) { continue; } // If adding this effect would exceed the max texture coord set count then generate a // new random effect. if (useFixedFunctionTexturing && !(*effect)->hasVertexCode()) { int numTransforms = (*effect)->numTransforms(); if (currTextureCoordSet + numTransforms > this->glCaps().maxFixedFunctionTextureCoords()) { continue; } currTextureCoordSet += numTransforms; } useFixedFunctionTexturing = useFixedFunctionTexturing && !(*effect)->hasVertexCode(); for (int i = 0; i < numAttribs; ++i) { attribIndices[i] = currAttribIndex++; } GrEffectStage* stage = SkNEW_ARGS(GrEffectStage, (effect.get(), attribIndices[0], attribIndices[1])); stages[s] = stage; ++s; } const GrTexture* dstTexture = random.nextBool() ? dummyTextures[0] : dummyTextures[1]; pdesc.setRandom(&random, this, dummyTextures[0]->asRenderTarget(), dstTexture, stages.get(), numColorStages, numCoverageStages, currAttribIndex); SkAutoTUnref<GrGLProgram> program(GrGLProgram::Create(this, pdesc, stages, stages + numColorStages)); for (int s = 0; s < numStages; ++s) { SkDELETE(stages[s]); } if (NULL == program.get()) { return false; } } return true; }