SK_API sk_sp<SkFontMgr> SkFontMgr_New_FCI(sk_sp<SkFontConfigInterface> fci) { SkASSERT(fci); return sk_make_sp<SkFontMgr_FCI>(std::move(fci)); }
void GrBitmapTextContext::drawText(const GrPaint& paint, const SkPaint& skPaint, const char text[], size_t byteLength, SkScalar x, SkScalar y) { SkASSERT(byteLength == 0 || text != NULL); // nothing to draw if (text == NULL || byteLength == 0 /*|| fRC->isEmpty()*/) { return; } this->init(paint, skPaint); if (NULL == fDrawTarget) { return; } SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc(); SkAutoGlyphCache autoCache(fSkPaint, &fDeviceProperties, &fContext->getMatrix()); SkGlyphCache* cache = autoCache.getCache(); GrFontScaler* fontScaler = GetGrFontScaler(cache); if (NULL == fStrike) { fStrike = fContext->getFontCache()->getStrike(fontScaler, false); } // transform our starting point { SkPoint loc; fContext->getMatrix().mapXY(x, y, &loc); x = loc.fX; y = loc.fY; } // need to measure first if (fSkPaint.getTextAlign() != SkPaint::kLeft_Align) { SkVector stop; MeasureText(cache, glyphCacheProc, text, byteLength, &stop); SkScalar stopX = stop.fX; SkScalar stopY = stop.fY; if (fSkPaint.getTextAlign() == SkPaint::kCenter_Align) { stopX = SkScalarHalf(stopX); stopY = SkScalarHalf(stopY); } x -= stopX; y -= stopY; } const char* stop = text + byteLength; // allocate vertices SkASSERT(NULL == fVertices); bool useColorVerts = kA8_GrMaskFormat == fStrike->getMaskFormat(); if (useColorVerts) { fDrawTarget->drawState()->setVertexAttribs<gTextVertexWithColorAttribs>( SK_ARRAY_COUNT(gTextVertexWithColorAttribs)); } else { fDrawTarget->drawState()->setVertexAttribs<gTextVertexAttribs>( SK_ARRAY_COUNT(gTextVertexAttribs)); } int numGlyphs = fSkPaint.textToGlyphs(text, byteLength, NULL); bool success = fDrawTarget->reserveVertexAndIndexSpace(4*numGlyphs, 0, &fVertices, NULL); GrAlwaysAssert(success); SkAutoKern autokern; SkFixed fxMask = ~0; SkFixed fyMask = ~0; SkFixed halfSampleX, halfSampleY; if (cache->isSubpixel()) { halfSampleX = halfSampleY = (SK_FixedHalf >> SkGlyph::kSubBits); SkAxisAlignment baseline = SkComputeAxisAlignmentForHText(fContext->getMatrix()); if (kX_SkAxisAlignment == baseline) { fyMask = 0; halfSampleY = SK_FixedHalf; } else if (kY_SkAxisAlignment == baseline) { fxMask = 0; halfSampleX = SK_FixedHalf; } } else {
static inline bool skpaint_to_grpaint_impl(GrContext* context, const GrColorSpaceInfo& colorSpaceInfo, const SkPaint& skPaint, const SkMatrix& viewM, std::unique_ptr<GrFragmentProcessor>* shaderProcessor, SkBlendMode* primColorMode, GrPaint* grPaint) { grPaint->setAllowSRGBInputs(colorSpaceInfo.isGammaCorrect()); // Convert SkPaint color to 4f format, including optional linearizing and gamut conversion. GrColor4f origColor = SkColorToUnpremulGrColor4f(skPaint.getColor(), colorSpaceInfo); const GrFPArgs fpArgs(context, &viewM, skPaint.getFilterQuality(), &colorSpaceInfo); // Setup the initial color considering the shader, the SkPaint color, and the presence or not // of per-vertex colors. std::unique_ptr<GrFragmentProcessor> shaderFP; if (!primColorMode || blend_requires_shader(*primColorMode)) { if (shaderProcessor) { shaderFP = std::move(*shaderProcessor); } else if (const auto* shader = as_SB(skPaint.getShader())) { shaderFP = shader->asFragmentProcessor(fpArgs); if (!shaderFP) { return false; } } } // Set this in below cases if the output of the shader/paint-color/paint-alpha/primXfermode is // a known constant value. In that case we can simply apply a color filter during this // conversion without converting the color filter to a GrFragmentProcessor. bool applyColorFilterToPaintColor = false; if (shaderFP) { if (primColorMode) { // There is a blend between the primitive color and the shader color. The shader sees // the opaque paint color. The shader's output is blended using the provided mode by // the primitive color. The blended color is then modulated by the paint's alpha. // The geometry processor will insert the primitive color to start the color chain, so // the GrPaint color will be ignored. GrColor4f shaderInput = origColor.opaque(); shaderFP = GrFragmentProcessor::OverrideInput(std::move(shaderFP), shaderInput); shaderFP = GrXfermodeFragmentProcessor::MakeFromSrcProcessor(std::move(shaderFP), *primColorMode); // The above may return null if compose results in a pass through of the prim color. if (shaderFP) { grPaint->addColorFragmentProcessor(std::move(shaderFP)); } // We can ignore origColor here - alpha is unchanged by gamma GrColor paintAlpha = SkColorAlphaToGrColor(skPaint.getColor()); if (GrColor_WHITE != paintAlpha) { // No gamut conversion - paintAlpha is a (linear) alpha value, splatted to all // color channels. It's value should be treated as the same in ANY color space. grPaint->addColorFragmentProcessor(GrConstColorProcessor::Make( GrColor4f::FromGrColor(paintAlpha), GrConstColorProcessor::InputMode::kModulateRGBA)); } } else { // The shader's FP sees the paint unpremul color grPaint->setColor4f(origColor); grPaint->addColorFragmentProcessor(std::move(shaderFP)); } } else { if (primColorMode) { // There is a blend between the primitive color and the paint color. The blend considers // the opaque paint color. The paint's alpha is applied to the post-blended color. auto processor = GrConstColorProcessor::Make(origColor.opaque(), GrConstColorProcessor::InputMode::kIgnore); processor = GrXfermodeFragmentProcessor::MakeFromSrcProcessor(std::move(processor), *primColorMode); if (processor) { grPaint->addColorFragmentProcessor(std::move(processor)); } grPaint->setColor4f(origColor.opaque()); // We can ignore origColor here - alpha is unchanged by gamma GrColor paintAlpha = SkColorAlphaToGrColor(skPaint.getColor()); if (GrColor_WHITE != paintAlpha) { // No gamut conversion - paintAlpha is a (linear) alpha value, splatted to all // color channels. It's value should be treated as the same in ANY color space. grPaint->addColorFragmentProcessor(GrConstColorProcessor::Make( GrColor4f::FromGrColor(paintAlpha), GrConstColorProcessor::InputMode::kModulateRGBA)); } } else { // No shader, no primitive color. grPaint->setColor4f(origColor.premul()); applyColorFilterToPaintColor = true; } } SkColorFilter* colorFilter = skPaint.getColorFilter(); if (colorFilter) { if (applyColorFilterToPaintColor) { // If we're in legacy mode, we *must* avoid using the 4f version of the color filter, // because that will combine with the linearized version of the stored color. if (colorSpaceInfo.isGammaCorrect()) { grPaint->setColor4f(GrColor4f::FromSkColor4f( colorFilter->filterColor4f(origColor.toSkColor4f())).premul()); } else { grPaint->setColor4f(SkColorToPremulGrColor4fLegacy( colorFilter->filterColor(skPaint.getColor()))); } } else { auto cfFP = colorFilter->asFragmentProcessor(context, colorSpaceInfo); if (cfFP) { grPaint->addColorFragmentProcessor(std::move(cfFP)); } else { return false; } } } SkMaskFilterBase* maskFilter = as_MFB(skPaint.getMaskFilter()); if (maskFilter) { if (auto mfFP = maskFilter->asFragmentProcessor(fpArgs)) { grPaint->addCoverageFragmentProcessor(std::move(mfFP)); } } // When the xfermode is null on the SkPaint (meaning kSrcOver) we need the XPFactory field on // the GrPaint to also be null (also kSrcOver). SkASSERT(!grPaint->getXPFactory()); if (!skPaint.isSrcOver()) { grPaint->setXPFactory(SkBlendMode_AsXPFactory(skPaint.getBlendMode())); } #ifndef SK_IGNORE_GPU_DITHER // Conservative default, in case GrPixelConfigToColorType() fails. SkColorType ct = SkColorType::kRGB_565_SkColorType; GrPixelConfigToColorType(colorSpaceInfo.config(), &ct); if (SkPaintPriv::ShouldDither(skPaint, ct) && grPaint->numColorFragmentProcessors() > 0 && !colorSpaceInfo.isGammaCorrect()) { auto ditherFP = GrDitherEffect::Make(colorSpaceInfo.config()); if (ditherFP) { grPaint->addColorFragmentProcessor(std::move(ditherFP)); } } #endif return true; }
void GrVkPipelineState::writeSamplers(GrVkGpu* gpu, const SkTArray<const GrTextureAccess*>& textureBindings) { SkASSERT(fNumSamplers == textureBindings.count()); for (int i = 0; i < textureBindings.count(); ++i) { const GrTextureParams& params = textureBindings[i]->getParams(); GrVkTexture* texture = static_cast<GrVkTexture*>(textureBindings[i]->getTexture()); if (GrTextureParams::kMipMap_FilterMode == params.filterMode()) { if (texture->texturePriv().mipMapsAreDirty()) { gpu->generateMipmap(texture); texture->texturePriv().dirtyMipMaps(false); } } fSamplers.push(gpu->resourceProvider().findOrCreateCompatibleSampler(params, texture->texturePriv().maxMipMapLevel())); const GrVkImage::Resource* textureResource = texture->resource(); textureResource->ref(); fTextures.push(textureResource); const GrVkImageView* textureView = texture->textureView(); textureView->ref(); fTextureViews.push(textureView); // Change texture layout so it can be read in shader VkImageLayout layout = texture->currentLayout(); VkPipelineStageFlags srcStageMask = GrVkMemory::LayoutToPipelineStageFlags(layout); VkPipelineStageFlags dstStageMask = VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT; VkAccessFlags srcAccessMask = GrVkMemory::LayoutToSrcAccessMask(layout); VkAccessFlags dstAccessMask = VK_ACCESS_SHADER_READ_BIT; texture->setImageLayout(gpu, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, srcAccessMask, dstAccessMask, srcStageMask, dstStageMask, false); VkDescriptorImageInfo imageInfo; memset(&imageInfo, 0, sizeof(VkDescriptorImageInfo)); imageInfo.sampler = fSamplers[i]->sampler(); imageInfo.imageView = texture->textureView()->imageView(); imageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; VkWriteDescriptorSet writeInfo; memset(&writeInfo, 0, sizeof(VkWriteDescriptorSet)); writeInfo.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; writeInfo.pNext = nullptr; writeInfo.dstSet = fDescriptorSets[GrVkUniformHandler::kSamplerDescSet]; writeInfo.dstBinding = i; writeInfo.dstArrayElement = 0; writeInfo.descriptorCount = 1; writeInfo.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; writeInfo.pImageInfo = &imageInfo; writeInfo.pBufferInfo = nullptr; writeInfo.pTexelBufferView = nullptr; GR_VK_CALL(gpu->vkInterface(), UpdateDescriptorSets(gpu->device(), 1, &writeInfo, 0, nullptr)); } }
GrPipeline* GrPipeline::CreateAt(void* memory, const CreateArgs& args, GrPipelineOptimizations* opts) { const GrPipelineBuilder& builder = *args.fPipelineBuilder; // Create XferProcessor from DS's XPFactory SkAutoTUnref<GrXferProcessor> xferProcessor( builder.getXPFactory()->createXferProcessor(args.fColorPOI, args.fCoveragePOI, builder.hasMixedSamples(), &args.fDstTexture, *args.fCaps)); if (!xferProcessor) { return nullptr; } GrColor overrideColor = GrColor_ILLEGAL; if (args.fColorPOI.firstEffectiveProcessorIndex() != 0) { overrideColor = args.fColorPOI.inputColorToFirstEffectiveProccesor(); } GrXferProcessor::OptFlags optFlags = GrXferProcessor::kNone_OptFlags; optFlags = xferProcessor->getOptimizations(args.fColorPOI, args.fCoveragePOI, builder.getStencil().doesWrite(), &overrideColor, *args.fCaps); // When path rendering the stencil settings are not always set on the GrPipelineBuilder // so we must check the draw type. In cases where we will skip drawing we simply return a // null GrPipeline. if (GrXferProcessor::kSkipDraw_OptFlag & optFlags) { return nullptr; } // No need to have an override color if it isn't even going to be used. if (SkToBool(GrXferProcessor::kIgnoreColor_OptFlag & optFlags)) { overrideColor = GrColor_ILLEGAL; } GrPipeline* pipeline = new (memory) GrPipeline; pipeline->fXferProcessor.reset(xferProcessor.get()); pipeline->fRenderTarget.reset(builder.fRenderTarget.get()); SkASSERT(pipeline->fRenderTarget); pipeline->fScissorState = *args.fScissor; pipeline->fStencilSettings = builder.getStencil(); pipeline->fDrawFace = builder.getDrawFace(); pipeline->fFlags = 0; if (builder.isHWAntialias()) { pipeline->fFlags |= kHWAA_Flag; } if (builder.isDither()) { pipeline->fFlags |= kDither_Flag; } if (builder.snapVerticesToPixelCenters()) { pipeline->fFlags |= kSnapVertices_Flag; } int firstColorProcessorIdx = args.fColorPOI.firstEffectiveProcessorIndex(); // TODO: Once we can handle single or four channel input into coverage GrFragmentProcessors // then we can use GrPipelineBuilder's coverageProcInfo (like color above) to set this initial // information. int firstCoverageProcessorIdx = 0; pipeline->adjustProgramFromOptimizations(builder, optFlags, args.fColorPOI, args.fCoveragePOI, &firstColorProcessorIdx, &firstCoverageProcessorIdx); bool usesLocalCoords = false; // Copy GrFragmentProcessors from GrPipelineBuilder to Pipeline pipeline->fNumColorProcessors = builder.numColorFragmentProcessors() - firstColorProcessorIdx; int numTotalProcessors = pipeline->fNumColorProcessors + builder.numCoverageFragmentProcessors() - firstCoverageProcessorIdx; pipeline->fFragmentProcessors.reset(numTotalProcessors); int currFPIdx = 0; for (int i = firstColorProcessorIdx; i < builder.numColorFragmentProcessors(); ++i, ++currFPIdx) { const GrFragmentProcessor* fp = builder.getColorFragmentProcessor(i); pipeline->fFragmentProcessors[currFPIdx].reset(fp); usesLocalCoords = usesLocalCoords || fp->usesLocalCoords(); fp->gatherCoordTransforms(&pipeline->fCoordTransforms); } for (int i = firstCoverageProcessorIdx; i < builder.numCoverageFragmentProcessors(); ++i, ++currFPIdx) { const GrFragmentProcessor* fp = builder.getCoverageFragmentProcessor(i); pipeline->fFragmentProcessors[currFPIdx].reset(fp); usesLocalCoords = usesLocalCoords || fp->usesLocalCoords(); fp->gatherCoordTransforms(&pipeline->fCoordTransforms); } // Setup info we need to pass to GrPrimitiveProcessors that are used with this GrPipeline. opts->fFlags = 0; if (!SkToBool(optFlags & GrXferProcessor::kIgnoreColor_OptFlag)) { opts->fFlags |= GrPipelineOptimizations::kReadsColor_Flag; } if (GrColor_ILLEGAL != overrideColor) { opts->fFlags |= GrPipelineOptimizations::kUseOverrideColor_Flag; opts->fOverrideColor = overrideColor; } if (!SkToBool(optFlags & GrXferProcessor::kIgnoreCoverage_OptFlag)) { opts->fFlags |= GrPipelineOptimizations::kReadsCoverage_Flag; } if (usesLocalCoords) { opts->fFlags |= GrPipelineOptimizations::kReadsLocalCoords_Flag; } if (SkToBool(optFlags & GrXferProcessor::kCanTweakAlphaForCoverage_OptFlag)) { opts->fFlags |= GrPipelineOptimizations::kCanTweakAlphaForCoverage_Flag; } GrXPFactory::InvariantBlendedColor blendedColor; builder.fXPFactory->getInvariantBlendedColor(args.fColorPOI, &blendedColor); if (blendedColor.fWillBlendWithDst) { opts->fFlags |= GrPipelineOptimizations::kWillColorBlendWithDst_Flag; } return pipeline; }
bool GrDrawTarget::checkDraw(GrPrimitiveType type, int startVertex, int startIndex, int vertexCount, int indexCount) const { const GrDrawState& drawState = this->getDrawState(); #ifdef SK_DEBUG const GeometrySrcState& geoSrc = fGeoSrcStateStack.back(); int maxVertex = startVertex + vertexCount; int maxValidVertex; switch (geoSrc.fVertexSrc) { case kNone_GeometrySrcType: SkFAIL("Attempting to draw without vertex src."); case kReserved_GeometrySrcType: // fallthrough case kArray_GeometrySrcType: maxValidVertex = geoSrc.fVertexCount; break; case kBuffer_GeometrySrcType: maxValidVertex = static_cast<int>(geoSrc.fVertexBuffer->gpuMemorySize() / geoSrc.fVertexSize); break; } if (maxVertex > maxValidVertex) { SkFAIL("Drawing outside valid vertex range."); } if (indexCount > 0) { int maxIndex = startIndex + indexCount; int maxValidIndex; switch (geoSrc.fIndexSrc) { case kNone_GeometrySrcType: SkFAIL("Attempting to draw indexed geom without index src."); case kReserved_GeometrySrcType: // fallthrough case kArray_GeometrySrcType: maxValidIndex = geoSrc.fIndexCount; break; case kBuffer_GeometrySrcType: maxValidIndex = static_cast<int>(geoSrc.fIndexBuffer->gpuMemorySize() / sizeof(uint16_t)); break; } if (maxIndex > maxValidIndex) { SkFAIL("Index reads outside valid index range."); } } SkASSERT(drawState.getRenderTarget()); if (drawState.hasGeometryProcessor()) { const GrGeometryProcessor* gp = drawState.getGeometryProcessor()->getProcessor(); int numTextures = gp->numTextures(); for (int t = 0; t < numTextures; ++t) { GrTexture* texture = gp->texture(t); SkASSERT(texture->asRenderTarget() != drawState.getRenderTarget()); } } for (int s = 0; s < drawState.numColorStages(); ++s) { const GrProcessor* effect = drawState.getColorStage(s).getProcessor(); int numTextures = effect->numTextures(); for (int t = 0; t < numTextures; ++t) { GrTexture* texture = effect->texture(t); SkASSERT(texture->asRenderTarget() != drawState.getRenderTarget()); } } for (int s = 0; s < drawState.numCoverageStages(); ++s) { const GrProcessor* effect = drawState.getCoverageStage(s).getProcessor(); int numTextures = effect->numTextures(); for (int t = 0; t < numTextures; ++t) { GrTexture* texture = effect->texture(t); SkASSERT(texture->asRenderTarget() != drawState.getRenderTarget()); } } SkASSERT(drawState.validateVertexAttribs()); #endif if (NULL == drawState.getRenderTarget()) { return false; } return true; }
void GrDrawTarget::DrawInfo::adjustStartIndex(int indexOffset) { SkASSERT(this->isIndexed()); fStartIndex += indexOffset; SkASSERT(fStartIndex >= 0); }
// Test out the non-degenerate RR cases static void test_round_rect_general(skiatest::Reporter* reporter) { static const SkScalar kEps = 0.1f; static const SkScalar kDist20 = 20 * (SK_Scalar1 - SK_ScalarRoot2Over2); static const SkPoint pts[] = { // Upper Left { kDist20 - kEps, kDist20 - kEps }, // out { kDist20 + kEps, kDist20 + kEps }, // in // Upper Right { kWidth + kEps - kDist20, kDist20 - kEps }, // out { kWidth - kEps - kDist20, kDist20 + kEps }, // in // Lower Right { kWidth + kEps - kDist20, kHeight + kEps - kDist20 }, // out { kWidth - kEps - kDist20, kHeight - kEps - kDist20 }, // in // Lower Left { kDist20 - kEps, kHeight + kEps - kDist20 }, //out { kDist20 + kEps, kHeight - kEps - kDist20 }, // in // Middle { SkIntToScalar(50), SkIntToScalar(50) } // in }; static const bool isIn[] = { false, true, false, true, false, true, false, true, true }; SkASSERT(SK_ARRAY_COUNT(pts) == SK_ARRAY_COUNT(isIn)); //---- SkRect rect = SkRect::MakeLTRB(0, 0, kWidth, kHeight); SkRRect rr1; rr1.setRectXY(rect, 20, 20); REPORTER_ASSERT(reporter, SkRRect::kSimple_Type == rr1.type()); for (size_t i = 0; i < SK_ARRAY_COUNT(pts); ++i) { REPORTER_ASSERT(reporter, isIn[i] == rr1.contains(pts[i].fX, pts[i].fY)); } //---- static const SkScalar kDist50 = 50*(SK_Scalar1 - SK_ScalarRoot2Over2); static const SkPoint pts2[] = { // Upper Left { -SK_Scalar1, -SK_Scalar1 }, // out { SK_Scalar1, SK_Scalar1 }, // in // Upper Right { kWidth + kEps - kDist20, kDist20 - kEps }, // out { kWidth - kEps - kDist20, kDist20 + kEps }, // in // Lower Right { kWidth + kEps - kDist50, kHeight + kEps - kDist50 }, // out { kWidth - kEps - kDist50, kHeight - kEps - kDist50 }, // in // Lower Left { kDist20 - kEps, kHeight + kEps - kDist50 }, // out { kDist20 + kEps, kHeight - kEps - kDist50 }, // in // Middle { SkIntToScalar(50), SkIntToScalar(50) } // in }; SkASSERT(SK_ARRAY_COUNT(pts2) == SK_ARRAY_COUNT(isIn)); SkPoint radii[4] = { { 0, 0 }, { 20, 20 }, { 50, 50 }, { 20, 50 } }; SkRRect rr2; rr2.setRectRadii(rect, radii); REPORTER_ASSERT(reporter, SkRRect::kComplex_Type == rr2.type()); for (size_t i = 0; i < SK_ARRAY_COUNT(pts); ++i) { REPORTER_ASSERT(reporter, isIn[i] == rr2.contains(pts2[i].fX, pts2[i].fY)); } }
size_t SkPDFStream::dataSize() const { SkASSERT(fDataStream->hasLength()); return fDataStream->getLength(); }
bool NativeInputWindowHandle::updateInfo() { AutoPtr<IInputWindowHandle> obj; mObjWeak->Resolve(EIID_IInputWindowHandle, (IInterface**)&obj); if (!obj) { releaseInfo(); return false; } if (!mInfo) { mInfo = new android::InputWindowInfo(); } else { mInfo->touchableRegion.clear(); } Elastos::Droid::Server::Input::InputWindowHandle* handle = (Elastos::Droid::Server::Input::InputWindowHandle*)obj.Get(); AutoPtr<IInputChannel> inputChannelObj = handle->mInputChannel; if (inputChannelObj) { Handle64 ptr; inputChannelObj->GetNativeInputChannel(&ptr); NativeInputChannel* nativeInputChannel = reinterpret_cast<NativeInputChannel*>(ptr); mInfo->inputChannel = nativeInputChannel != NULL ? nativeInputChannel->getInputChannel() : NULL; } else { mInfo->inputChannel.clear(); } if (!handle->mName.IsNull()) { mInfo->name.setTo(handle->mName.string()); } else { mInfo->name.setTo("<null>"); } mInfo->layoutParamsFlags = handle->mLayoutParamsFlags; mInfo->layoutParamsType = handle->mLayoutParamsType; mInfo->dispatchingTimeout = handle->mDispatchingTimeoutNanos; mInfo->frameLeft = handle->mFrameLeft; mInfo->frameTop = handle->mFrameTop; mInfo->frameRight = handle->mFrameRight; mInfo->frameBottom = handle->mFrameBottom; mInfo->scaleFactor = handle->mScaleFactor; AutoPtr<IRegion> regionObj = handle->mTouchableRegion; if (regionObj) { Int64 regionHandle; regionObj->GetNativeRegion((Handle64*)®ionHandle); SkRegion* region = reinterpret_cast<SkRegion*>(regionHandle); SkASSERT(region != NULL); for (SkRegion::Iterator it(*region); !it.done(); it.next()) { const SkIRect& rect = it.rect(); mInfo->addTouchableRegion(android::Rect(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom)); } } mInfo->visible = handle->mVisible; mInfo->canReceiveKeys = handle->mCanReceiveKeys; mInfo->hasFocus = handle->mHasFocus; mInfo->hasWallpaper = handle->mHasWallpaper; mInfo->paused = handle->mPaused; mInfo->layer = handle->mLayer; mInfo->ownerPid = handle->mOwnerPid; mInfo->ownerUid = handle->mOwnerUid; mInfo->inputFeatures = handle->mInputFeatures; mInfo->displayId = handle->mDisplayId; return true; }
// Test out the cases when the RR degenerates to a rect static void test_round_rect_rects(skiatest::Reporter* reporter) { SkRect r; static const SkPoint pts[] = { // Upper Left { -SK_Scalar1, -SK_Scalar1 }, // out { SK_Scalar1, SK_Scalar1 }, // in // Upper Right { SkIntToScalar(101), -SK_Scalar1}, // out { SkIntToScalar(99), SK_Scalar1 }, // in // Lower Right { SkIntToScalar(101), SkIntToScalar(101) }, // out { SkIntToScalar(99), SkIntToScalar(99) }, // in // Lower Left { -SK_Scalar1, SkIntToScalar(101) }, // out { SK_Scalar1, SkIntToScalar(99) }, // in // Middle { SkIntToScalar(50), SkIntToScalar(50) } // in }; static const bool isIn[] = { false, true, false, true, false, true, false, true, true }; SkASSERT(SK_ARRAY_COUNT(pts) == SK_ARRAY_COUNT(isIn)); //---- SkRRect empty; empty.setEmpty(); REPORTER_ASSERT(reporter, SkRRect::kEmpty_Type == empty.type()); r = empty.rect(); REPORTER_ASSERT(reporter, 0 == r.fLeft && 0 == r.fTop && 0 == r.fRight && 0 == r.fBottom); //---- SkRect rect = SkRect::MakeLTRB(0, 0, kWidth, kHeight); SkRRect rr1; rr1.setRectXY(rect, 0, 0); REPORTER_ASSERT(reporter, SkRRect::kRect_Type == rr1.type()); r = rr1.rect(); REPORTER_ASSERT(reporter, rect == r); for (size_t i = 0; i < SK_ARRAY_COUNT(pts); ++i) { REPORTER_ASSERT(reporter, isIn[i] == rr1.contains(pts[i].fX, pts[i].fY)); } //---- SkPoint radii[4] = { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }; SkRRect rr2; rr2.setRectRadii(rect, radii); REPORTER_ASSERT(reporter, SkRRect::kRect_Type == rr2.type()); r = rr2.rect(); REPORTER_ASSERT(reporter, rect == r); for (size_t i = 0; i < SK_ARRAY_COUNT(pts); ++i) { REPORTER_ASSERT(reporter, isIn[i] == rr2.contains(pts[i].fX, pts[i].fY)); } //---- SkPoint radii2[4] = { { 0, 0 }, { 20, 20 }, { 50, 50 }, { 20, 50 } }; SkRRect rr3; rr3.setRectRadii(rect, radii2); REPORTER_ASSERT(reporter, SkRRect::kComplex_Type == rr3.type()); }
~AutoCachePurge() { SkASSERT(fXformer->fReentryCount > 0); if (--fXformer->fReentryCount == 0) { fXformer->purgeCaches(); } }
SkTypeface* createTypeface(int index) override { SkASSERT(false); return nullptr; }
void getStyle(int index, SkFontStyle*, SkString* style) override { SkASSERT(false); }
void GrResourceEntry::validate() const { SkASSERT(fResource); SkASSERT(fResource->getCacheEntry() == this); fResource->validate(); }
SkDrawTo::~SkDrawTo() { SkASSERT(0); }
SkString GrDrawTargetCaps::dump() const { SkString r; static const char* gNY[] = {"NO", "YES"}; r.appendf("MIP Map Support : %s\n", gNY[fMipMapSupport]); r.appendf("NPOT Texture Tile Support : %s\n", gNY[fNPOTTextureTileSupport]); r.appendf("Two Sided Stencil Support : %s\n", gNY[fTwoSidedStencilSupport]); r.appendf("Stencil Wrap Ops Support : %s\n", gNY[fStencilWrapOpsSupport]); r.appendf("HW AA Lines Support : %s\n", gNY[fHWAALineSupport]); r.appendf("Shader Derivative Support : %s\n", gNY[fShaderDerivativeSupport]); r.appendf("Geometry Shader Support : %s\n", gNY[fGeometryShaderSupport]); r.appendf("Dual Source Blending Support : %s\n", gNY[fDualSourceBlendingSupport]); r.appendf("Path Rendering Support : %s\n", gNY[fPathRenderingSupport]); r.appendf("Dst Read In Shader Support : %s\n", gNY[fDstReadInShaderSupport]); r.appendf("Discard Render Target Support: %s\n", gNY[fDiscardRenderTargetSupport]); r.appendf("Reuse Scratch Textures : %s\n", gNY[fReuseScratchTextures]); r.appendf("Gpu Tracing Support : %s\n", gNY[fGpuTracingSupport]); r.appendf("Compressed Update Support : %s\n", gNY[fCompressedTexSubImageSupport]); r.appendf("Max Texture Size : %d\n", fMaxTextureSize); r.appendf("Max Render Target Size : %d\n", fMaxRenderTargetSize); r.appendf("Max Sample Count : %d\n", fMaxSampleCount); r.appendf("Map Buffer Support : %s\n", map_flags_to_string(fMapBufferFlags).c_str()); static const char* kConfigNames[] = { "Unknown", // kUnknown_GrPixelConfig "Alpha8", // kAlpha_8_GrPixelConfig, "Index8", // kIndex_8_GrPixelConfig, "RGB565", // kRGB_565_GrPixelConfig, "RGBA444", // kRGBA_4444_GrPixelConfig, "RGBA8888", // kRGBA_8888_GrPixelConfig, "BGRA8888", // kBGRA_8888_GrPixelConfig, "ETC1", // kETC1_GrPixelConfig, "LATC", // kLATC_GrPixelConfig, "R11EAC", // kR11_EAC_GrPixelConfig, "ASTC12x12",// kASTC_12x12_GrPixelConfig, "RGBAFloat", // kRGBA_float_GrPixelConfig }; GR_STATIC_ASSERT(0 == kUnknown_GrPixelConfig); GR_STATIC_ASSERT(1 == kAlpha_8_GrPixelConfig); GR_STATIC_ASSERT(2 == kIndex_8_GrPixelConfig); GR_STATIC_ASSERT(3 == kRGB_565_GrPixelConfig); GR_STATIC_ASSERT(4 == kRGBA_4444_GrPixelConfig); GR_STATIC_ASSERT(5 == kRGBA_8888_GrPixelConfig); GR_STATIC_ASSERT(6 == kBGRA_8888_GrPixelConfig); GR_STATIC_ASSERT(7 == kETC1_GrPixelConfig); GR_STATIC_ASSERT(8 == kLATC_GrPixelConfig); GR_STATIC_ASSERT(9 == kR11_EAC_GrPixelConfig); GR_STATIC_ASSERT(10 == kASTC_12x12_GrPixelConfig); GR_STATIC_ASSERT(11 == kRGBA_float_GrPixelConfig); GR_STATIC_ASSERT(SK_ARRAY_COUNT(kConfigNames) == kGrPixelConfigCnt); SkASSERT(!fConfigRenderSupport[kUnknown_GrPixelConfig][0]); SkASSERT(!fConfigRenderSupport[kUnknown_GrPixelConfig][1]); for (size_t i = 1; i < SK_ARRAY_COUNT(kConfigNames); ++i) { r.appendf("%s is renderable: %s, with MSAA: %s\n", kConfigNames[i], gNY[fConfigRenderSupport[i][0]], gNY[fConfigRenderSupport[i][1]]); } SkASSERT(!fConfigTextureSupport[kUnknown_GrPixelConfig]); for (size_t i = 1; i < SK_ARRAY_COUNT(kConfigNames); ++i) { r.appendf("%s is uploadable to a texture: %s\n", kConfigNames[i], gNY[fConfigTextureSupport[i]]); } return r; }
const SkDisplayEnumMap& SkAnimatorScript::GetEnumValues(SkDisplayTypes type) { int index = SkTSearch<SkDisplayTypes>(&gEnumMaps[0].fType, gEnumMapCount, type, sizeof(SkDisplayEnumMap)); SkASSERT(index >= 0); return gEnumMaps[index]; }
void GrDrawTarget::DrawInfo::adjustStartVertex(int vertexOffset) { fStartVertex += vertexOffset; SkASSERT(fStartVertex >= 0); }
DEF_TEST(SkpSkGr, reporter) { SkTArray<TestResult, true> errors; if (!initTest()) { return; } SkpSkGrThreadState state; state.init(0); int smallCount = 0; for (int dirNo = 1; dirNo <= 100; ++dirNo) { SkString pictDir = make_in_dir_name(dirNo); SkASSERT(pictDir.size()); if (reporter->verbose()) { SkDebugf("dirNo=%d\n", dirNo); } SkOSFile::Iter iter(pictDir.c_str(), "skp"); SkString filename; int testCount = 0; PreParser preParser(dirNo); SkFILEWStream statusStream(makeStatusString(dirNo).c_str()); while (iter.next(&filename)) { for (size_t index = 0; index < skipOverSkGrCount; ++index) { if (skipOverSkGr[index].directory == dirNo && strcmp(filename.c_str(), skipOverSkGr[index].filename) == 0) { goto skipOver; } } if (preParser.match(filename, &statusStream, &state.fResult)) { addError(&state); ++testCount; goto checkEarlyExit; } if (state.fSmallestError > 5000000) { goto breakOut; } { TestResult& result = state.fResult; result.test(dirNo, filename); SkString outStr(result.status()); statusStream.write(outStr.c_str(), outStr.size()); statusStream.flush(); if (1) { SkDebugf("%s", outStr.c_str()); } bool noMatch = addError(&state); if (noMatch) { smallCount = 0; } else if (++smallCount > 10000) { goto breakOut; } } ++testCount; if (reporter->verbose()) { if (testCount % 100 == 0) { SkDebugf("#%d\n", testCount); } } skipOver: reporter->bumpTestCount(); checkEarlyExit: if (1 && testCount == 20) { break; } } } breakOut: if (reporter->verbose()) { for (int index = 0; index < state.fFoundCount; ++index) { SkDebugf("%d %s %d\n", state.fDirsFound[index], state.fFilesFound[index], state.fError[index]); } } for (int index = 0; index < state.fFoundCount; ++index) { TestResult::Test(state.fDirsFound[index], state.fFilesFound[index], kEncodeFiles, reporter->verbose()); if (reporter->verbose()) SkDebugf("+"); } }
static SkTypeface::Encoding paint2encoding(const SkPaint& paint) { SkPaint::TextEncoding enc = paint.getTextEncoding(); SkASSERT(SkPaint::kGlyphID_TextEncoding != enc); return (SkTypeface::Encoding)enc; }
void SkBitmapDevice::replaceBitmapBackendForRasterSurface(const SkBitmap& bm) { SkASSERT(bm.width() == fBitmap.width()); SkASSERT(bm.height() == fBitmap.height()); fBitmap = bm; // intent is to use bm's pixelRef (and rowbytes/config) fBitmap.lockPixels(); }
GrTexture* GaussianBlur(GrContext* context, GrTexture* srcTexture, bool canClobberSrc, const SkRect& rect, bool cropToRect, float sigmaX, float sigmaY) { SkASSERT(NULL != context); GrContext::AutoRenderTarget art(context); GrContext::AutoMatrix am; am.setIdentity(context); SkIRect clearRect; int scaleFactorX, radiusX; int scaleFactorY, radiusY; sigmaX = adjust_sigma(sigmaX, &scaleFactorX, &radiusX); sigmaY = adjust_sigma(sigmaY, &scaleFactorY, &radiusY); SkRect srcRect(rect); scale_rect(&srcRect, 1.0f / scaleFactorX, 1.0f / scaleFactorY); srcRect.roundOut(); scale_rect(&srcRect, static_cast<float>(scaleFactorX), static_cast<float>(scaleFactorY)); GrContext::AutoClip acs(context, SkRect::MakeWH(srcRect.width(), srcRect.height())); SkASSERT(kBGRA_8888_GrPixelConfig == srcTexture->config() || kRGBA_8888_GrPixelConfig == srcTexture->config() || kAlpha_8_GrPixelConfig == srcTexture->config()); GrTextureDesc desc; desc.fFlags = kRenderTarget_GrTextureFlagBit | kNoStencil_GrTextureFlagBit; desc.fWidth = SkScalarFloorToInt(srcRect.width()); desc.fHeight = SkScalarFloorToInt(srcRect.height()); desc.fConfig = srcTexture->config(); GrAutoScratchTexture temp1, temp2; GrTexture* dstTexture = temp1.set(context, desc); GrTexture* tempTexture = canClobberSrc ? srcTexture : temp2.set(context, desc); if (NULL == dstTexture || NULL == tempTexture) { return NULL; } for (int i = 1; i < scaleFactorX || i < scaleFactorY; i *= 2) { GrPaint paint; SkMatrix matrix; matrix.setIDiv(srcTexture->width(), srcTexture->height()); context->setRenderTarget(dstTexture->asRenderTarget()); SkRect dstRect(srcRect); if (cropToRect && i == 1) { dstRect.offset(-dstRect.fLeft, -dstRect.fTop); SkRect domain; matrix.mapRect(&domain, rect); domain.inset(i < scaleFactorX ? SK_ScalarHalf / srcTexture->width() : 0.0f, i < scaleFactorY ? SK_ScalarHalf / srcTexture->height() : 0.0f); SkAutoTUnref<GrEffectRef> effect(GrTextureDomainEffect::Create( srcTexture, matrix, domain, GrTextureDomain::kDecal_Mode, GrTextureParams::kBilerp_FilterMode)); paint.addColorEffect(effect); } else { GrTextureParams params(SkShader::kClamp_TileMode, GrTextureParams::kBilerp_FilterMode); paint.addColorTextureEffect(srcTexture, matrix, params); } scale_rect(&dstRect, i < scaleFactorX ? 0.5f : 1.0f, i < scaleFactorY ? 0.5f : 1.0f); context->drawRectToRect(paint, dstRect, srcRect); srcRect = dstRect; srcTexture = dstTexture; SkTSwap(dstTexture, tempTexture); } SkIRect srcIRect; srcRect.roundOut(&srcIRect); if (sigmaX > 0.0f) { if (scaleFactorX > 1) { // Clear out a radius to the right of the srcRect to prevent the // X convolution from reading garbage. clearRect = SkIRect::MakeXYWH(srcIRect.fRight, srcIRect.fTop, radiusX, srcIRect.height()); context->clear(&clearRect, 0x0, false); } context->setRenderTarget(dstTexture->asRenderTarget()); SkRect dstRect = SkRect::MakeWH(srcRect.width(), srcRect.height()); convolve_gaussian(context, srcRect, dstRect, srcTexture, Gr1DKernelEffect::kX_Direction, radiusX, sigmaX, cropToRect); srcTexture = dstTexture; srcRect = dstRect; SkTSwap(dstTexture, tempTexture); } if (sigmaY > 0.0f) { if (scaleFactorY > 1 || sigmaX > 0.0f) { // Clear out a radius below the srcRect to prevent the Y // convolution from reading garbage. clearRect = SkIRect::MakeXYWH(srcIRect.fLeft, srcIRect.fBottom, srcIRect.width(), radiusY); context->clear(&clearRect, 0x0, false); } context->setRenderTarget(dstTexture->asRenderTarget()); SkRect dstRect = SkRect::MakeWH(srcRect.width(), srcRect.height()); convolve_gaussian(context, srcRect, dstRect, srcTexture, Gr1DKernelEffect::kY_Direction, radiusY, sigmaY, cropToRect); srcTexture = dstTexture; srcRect = dstRect; SkTSwap(dstTexture, tempTexture); } if (scaleFactorX > 1 || scaleFactorY > 1) { // Clear one pixel to the right and below, to accommodate bilinear // upsampling. clearRect = SkIRect::MakeXYWH(srcIRect.fLeft, srcIRect.fBottom, srcIRect.width() + 1, 1); context->clear(&clearRect, 0x0, false); clearRect = SkIRect::MakeXYWH(srcIRect.fRight, srcIRect.fTop, 1, srcIRect.height()); context->clear(&clearRect, 0x0, false); SkMatrix matrix; matrix.setIDiv(srcTexture->width(), srcTexture->height()); context->setRenderTarget(dstTexture->asRenderTarget()); GrPaint paint; // FIXME: this should be mitchell, not bilinear. GrTextureParams params(SkShader::kClamp_TileMode, GrTextureParams::kBilerp_FilterMode); paint.addColorTextureEffect(srcTexture, matrix, params); SkRect dstRect(srcRect); scale_rect(&dstRect, (float) scaleFactorX, (float) scaleFactorY); context->drawRectToRect(paint, dstRect, srcRect); srcRect = dstRect; srcTexture = dstTexture; SkTSwap(dstTexture, tempTexture); } if (srcTexture == temp1.texture()) { return temp1.detach(); } else if (srcTexture == temp2.texture()) { return temp2.detach(); } else { srcTexture->ref(); return srcTexture; } }
SkBitmapDevice::SkBitmapDevice(const SkBitmap& bitmap) : fBitmap(bitmap) { SkASSERT(valid_for_bitmap_device(bitmap.info(), NULL)); }
void Font::drawGlyphs(GraphicsContext* gc, const SimpleFontData* font, const GlyphBuffer& glyphBuffer, int from, int numGlyphs, const FloatPoint& point) const { SkASSERT(sizeof(GlyphBufferGlyph) == sizeof(uint16_t)); // compile-time assert const GlyphBufferGlyph* glyphs = glyphBuffer.glyphs(from); SkScalar x = SkFloatToScalar(point.x()); SkScalar y = SkFloatToScalar(point.y()); // FIXME: text rendering speed: // Android has code in their WebCore fork to special case when the // GlyphBuffer has no advances other than the defaults. In that case the // text drawing can proceed faster. However, it's unclear when those // patches may be upstreamed to WebKit so we always use the slower path // here. const GlyphBufferAdvance* adv = glyphBuffer.advances(from); SkAutoSTMalloc<32, SkPoint> storage(numGlyphs); SkPoint* pos = storage.get(); for (int i = 0; i < numGlyphs; i++) { pos[i].set(x, y); x += SkFloatToScalar(adv[i].width()); y += SkFloatToScalar(adv[i].height()); } gc->platformContext()->prepareForSoftwareDraw(); SkCanvas* canvas = gc->platformContext()->canvas(); int textMode = gc->platformContext()->getTextDrawingMode(); // We draw text up to two times (once for fill, once for stroke). if (textMode & cTextFill) { SkPaint paint; gc->platformContext()->setupPaintForFilling(&paint); font->platformData().setupPaint(&paint); adjustTextRenderMode(&paint, gc->platformContext()); paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); paint.setColor(gc->fillColor().rgb()); canvas->drawPosText(glyphs, numGlyphs << 1, pos, paint); } if ((textMode & cTextStroke) && gc->platformContext()->getStrokeStyle() != NoStroke && gc->platformContext()->getStrokeThickness() > 0) { SkPaint paint; gc->platformContext()->setupPaintForStroking(&paint, 0, 0); font->platformData().setupPaint(&paint); adjustTextRenderMode(&paint, gc->platformContext()); paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); paint.setColor(gc->strokeColor().rgb()); if (textMode & cTextFill) { // If we also filled, we don't want to draw shadows twice. // See comment in FontChromiumWin.cpp::paintSkiaText() for more details. paint.setLooper(0)->safeUnref(); } canvas->drawPosText(glyphs, numGlyphs << 1, pos, paint); } }
SkBitmapDevice::SkBitmapDevice(const SkBitmap& bitmap, const SkDeviceProperties& deviceProperties) : SkBaseDevice(deviceProperties) , fBitmap(bitmap) { SkASSERT(valid_for_bitmap_device(bitmap.info(), NULL)); }
void GrBitmapTextContext::flushGlyphs() { if (NULL == fDrawTarget) { return; } GrDrawState* drawState = fDrawTarget->drawState(); GrDrawState::AutoRestoreEffects are(drawState); drawState->setFromPaint(fPaint, SkMatrix::I(), fContext->getRenderTarget()); if (fCurrVertex > 0) { // setup our sampler state for our text texture/atlas SkASSERT(SkIsAlign4(fCurrVertex)); GrTextureParams params(SkShader::kRepeat_TileMode, GrTextureParams::kNone_FilterMode); GrTexture* currTexture = fStrike->getTexture(); SkASSERT(currTexture); uint32_t textureUniqueID = currTexture->getUniqueID(); if (textureUniqueID != fEffectTextureUniqueID) { fCachedEffect.reset(GrCustomCoordsTextureEffect::Create(currTexture, params)); fEffectTextureUniqueID = textureUniqueID; } // This effect could be stored with one of the cache objects (atlas?) int coordsIdx = drawState->hasColorVertexAttribute() ? kGlyphCoordsWithColorAttributeIndex : kGlyphCoordsNoColorAttributeIndex; drawState->addCoverageEffect(fCachedEffect.get(), coordsIdx); SkASSERT(NULL != fStrike); switch (fStrike->getMaskFormat()) { // Color bitmap text case kARGB_GrMaskFormat: SkASSERT(!drawState->hasColorVertexAttribute()); drawState->setBlendFunc(fPaint.getSrcBlendCoeff(), fPaint.getDstBlendCoeff()); drawState->setColor(0xffffffff); break; // LCD text case kA888_GrMaskFormat: case kA565_GrMaskFormat: { if (kOne_GrBlendCoeff != fPaint.getSrcBlendCoeff() || kISA_GrBlendCoeff != fPaint.getDstBlendCoeff() || fPaint.numColorStages()) { GrPrintf("LCD Text will not draw correctly.\n"); } SkASSERT(!drawState->hasColorVertexAttribute()); // We don't use the GrPaint's color in this case because it's been premultiplied by // alpha. Instead we feed in a non-premultiplied color, and multiply its alpha by // the mask texture color. The end result is that we get // mask*paintAlpha*paintColor + (1-mask*paintAlpha)*dstColor int a = SkColorGetA(fSkPaint.getColor()); // paintAlpha drawState->setColor(SkColorSetARGB(a, a, a, a)); // paintColor drawState->setBlendConstant(skcolor_to_grcolor_nopremultiply(fSkPaint.getColor())); drawState->setBlendFunc(kConstC_GrBlendCoeff, kISC_GrBlendCoeff); break; } // Grayscale/BW text case kA8_GrMaskFormat: // set back to normal in case we took LCD path previously. drawState->setBlendFunc(fPaint.getSrcBlendCoeff(), fPaint.getDstBlendCoeff()); //drawState->setColor(fPaint.getColor()); // We're using per-vertex color. SkASSERT(drawState->hasColorVertexAttribute()); drawState->setColor(0xFFFFFFFF); break; default: SkFAIL("Unexepected mask format."); } int nGlyphs = fCurrVertex / 4; fDrawTarget->setIndexSourceToBuffer(fContext->getQuadIndexBuffer()); fDrawTarget->drawIndexedInstances(kTriangles_GrPrimitiveType, nGlyphs, 4, 6, &fVertexBounds); fCurrVertex = 0; fVertexBounds.setLargestInverted(); } fDrawTarget->resetVertexSource(); fVertices = NULL; }
GrResourceEntry::GrResourceEntry(const GrResourceKey& key, GrResource* resource) : fKey(key), fResource(resource) { // we assume ownership of the resource, and will unref it when we die SkASSERT(resource); resource->ref(); }
void GrResourceCache::validate() const { fList.validate(); fExclusiveList.validate(); SkASSERT(both_zero_or_nonzero(fEntryCount, fEntryBytes)); SkASSERT(both_zero_or_nonzero(fClientDetachedCount, fClientDetachedBytes)); SkASSERT(fClientDetachedBytes <= fEntryBytes); SkASSERT(fClientDetachedCount <= fEntryCount); SkASSERT((fEntryCount - fClientDetachedCount) == fCache.count()); EntryList::Iter iter; // check that the exclusively held entries are okay const GrResourceCacheEntry* entry = iter.init(const_cast<EntryList&>(fExclusiveList), EntryList::Iter::kHead_IterStart); for ( ; NULL != entry; entry = iter.next()) { entry->validate(); } // check that the shareable entries are okay entry = iter.init(const_cast<EntryList&>(fList), EntryList::Iter::kHead_IterStart); int count = 0; for ( ; NULL != entry; entry = iter.next()) { entry->validate(); SkASSERT(fCache.find(entry->key())); count += 1; } SkASSERT(count == fEntryCount - fClientDetachedCount); size_t bytes = countBytes(fList); SkASSERT(bytes == fEntryBytes - fClientDetachedBytes); bytes = countBytes(fExclusiveList); SkASSERT(bytes == fClientDetachedBytes); SkASSERT(fList.countEntries() == fEntryCount - fClientDetachedCount); SkASSERT(fExclusiveList.countEntries() == fClientDetachedCount); }
bool BGRAConvolve2D(const unsigned char* sourceData, int sourceByteRowStride, bool sourceHasAlpha, const SkConvolutionFilter1D& filterX, const SkConvolutionFilter1D& filterY, int outputByteRowStride, unsigned char* output, const SkConvolutionProcs& convolveProcs, bool useSimdIfPossible) { int maxYFilterSize = filterY.maxFilter(); // The next row in the input that we will generate a horizontally // convolved row for. If the filter doesn't start at the beginning of the // image (this is the case when we are only resizing a subset), then we // don't want to generate any output rows before that. Compute the starting // row for convolution as the first pixel for the first vertical filter. int filterOffset, filterLength; const SkConvolutionFilter1D::ConvolutionFixed* filterValues = filterY.FilterForValue(0, &filterOffset, &filterLength); int nextXRow = filterOffset; // We loop over each row in the input doing a horizontal convolution. This // will result in a horizontally convolved image. We write the results into // a circular buffer of convolved rows and do vertical convolution as rows // are available. This prevents us from having to store the entire // intermediate image and helps cache coherency. // We will need four extra rows to allow horizontal convolution could be done // simultaneously. We also pad each row in row buffer to be aligned-up to // 16 bytes. // TODO(jiesun): We do not use aligned load from row buffer in vertical // convolution pass yet. Somehow Windows does not like it. int rowBufferWidth = (filterX.numValues() + 15) & ~0xF; int rowBufferHeight = maxYFilterSize + (convolveProcs.fConvolve4RowsHorizontally ? 4 : 0); // check for too-big allocation requests : crbug.com/528628 { int64_t size = sk_64_mul(rowBufferWidth, rowBufferHeight); // need some limit, to avoid over-committing success from malloc, but then // crashing when we try to actually use the memory. // 100meg seems big enough to allow "normal" zoom factors and image sizes through // while avoiding the crash seen by the bug (crbug.com/528628) if (size > 100 * 1024 * 1024) { // SkDebugf("BGRAConvolve2D: tmp allocation [%lld] too big\n", size); return false; } } CircularRowBuffer rowBuffer(rowBufferWidth, rowBufferHeight, filterOffset); // Loop over every possible output row, processing just enough horizontal // convolutions to run each subsequent vertical convolution. SkASSERT(outputByteRowStride >= filterX.numValues() * 4); int numOutputRows = filterY.numValues(); // We need to check which is the last line to convolve before we advance 4 // lines in one iteration. int lastFilterOffset, lastFilterLength; // SSE2 can access up to 3 extra pixels past the end of the // buffer. At the bottom of the image, we have to be careful // not to access data past the end of the buffer. Normally // we fall back to the C++ implementation for the last row. // If the last row is less than 3 pixels wide, we may have to fall // back to the C++ version for more rows. Compute how many // rows we need to avoid the SSE implementation for here. filterX.FilterForValue(filterX.numValues() - 1, &lastFilterOffset, &lastFilterLength); int avoidSimdRows = 1 + convolveProcs.fExtraHorizontalReads / (lastFilterOffset + lastFilterLength); filterY.FilterForValue(numOutputRows - 1, &lastFilterOffset, &lastFilterLength); for (int outY = 0; outY < numOutputRows; outY++) { filterValues = filterY.FilterForValue(outY, &filterOffset, &filterLength); // Generate output rows until we have enough to run the current filter. while (nextXRow < filterOffset + filterLength) { if (convolveProcs.fConvolve4RowsHorizontally && nextXRow + 3 < lastFilterOffset + lastFilterLength - avoidSimdRows) { const unsigned char* src[4]; unsigned char* outRow[4]; for (int i = 0; i < 4; ++i) { src[i] = &sourceData[(uint64_t)(nextXRow + i) * sourceByteRowStride]; outRow[i] = rowBuffer.advanceRow(); } convolveProcs.fConvolve4RowsHorizontally(src, filterX, outRow, 4*rowBufferWidth); nextXRow += 4; } else { // Check if we need to avoid SSE2 for this row. if (convolveProcs.fConvolveHorizontally && nextXRow < lastFilterOffset + lastFilterLength - avoidSimdRows) { convolveProcs.fConvolveHorizontally( &sourceData[(uint64_t)nextXRow * sourceByteRowStride], filterX, rowBuffer.advanceRow(), sourceHasAlpha); } else { if (sourceHasAlpha) { ConvolveHorizontallyAlpha( &sourceData[(uint64_t)nextXRow * sourceByteRowStride], filterX, rowBuffer.advanceRow()); } else { ConvolveHorizontallyNoAlpha( &sourceData[(uint64_t)nextXRow * sourceByteRowStride], filterX, rowBuffer.advanceRow()); } } nextXRow++; } } // Compute where in the output image this row of final data will go. unsigned char* curOutputRow = &output[(uint64_t)outY * outputByteRowStride]; // Get the list of rows that the circular buffer has, in order. int firstRowInCircularBuffer; unsigned char* const* rowsToConvolve = rowBuffer.GetRowAddresses(&firstRowInCircularBuffer); // Now compute the start of the subset of those rows that the filter // needs. unsigned char* const* firstRowForFilter = &rowsToConvolve[filterOffset - firstRowInCircularBuffer]; if (convolveProcs.fConvolveVertically) { convolveProcs.fConvolveVertically(filterValues, filterLength, firstRowForFilter, filterX.numValues(), curOutputRow, sourceHasAlpha); } else { ConvolveVertically(filterValues, filterLength, firstRowForFilter, filterX.numValues(), curOutputRow, sourceHasAlpha); } } return true; }