Example #1
0
void SkRRect::setNinePatch(const SkRect& rect, SkScalar leftRad, SkScalar topRad,
                           SkScalar rightRad, SkScalar bottomRad) {
    fRect = rect;
    fRect.sort();

    if (fRect.isEmpty() || !fRect.isFinite()) {
        this->setEmpty();
        return;
    }

    const SkScalar array[4] = { leftRad, topRad, rightRad, bottomRad };
    if (!SkScalarsAreFinite(array, 4)) {
        this->setRect(rect);    // devolve into a simple rect
        return;
    }

    leftRad = SkMaxScalar(leftRad, 0);
    topRad = SkMaxScalar(topRad, 0);
    rightRad = SkMaxScalar(rightRad, 0);
    bottomRad = SkMaxScalar(bottomRad, 0);

    SkScalar scale = SK_Scalar1;
    if (leftRad + rightRad > fRect.width()) {
        scale = fRect.width() / (leftRad + rightRad);
    }
    if (topRad + bottomRad > fRect.height()) {
        scale = SkMinScalar(scale, fRect.height() / (topRad + bottomRad));
    }

    if (scale < SK_Scalar1) {
        leftRad = SkScalarMul(leftRad, scale);
        topRad = SkScalarMul(topRad, scale);
        rightRad = SkScalarMul(rightRad, scale);
        bottomRad = SkScalarMul(bottomRad, scale);
    }

    if (leftRad == rightRad && topRad == bottomRad) {
        if (leftRad >= SkScalarHalf(fRect.width()) && topRad >= SkScalarHalf(fRect.height())) {
            fType = kOval_Type;
        } else if (0 == leftRad || 0 == topRad) {
            // If the left and (by equality check above) right radii are zero then it is a rect.
            // Same goes for top/bottom.
            fType = kRect_Type;
            leftRad = 0;
            topRad = 0;
            rightRad = 0;
            bottomRad = 0;
        } else {
            fType = kSimple_Type;
        }
    } else {
        fType = kNinePatch_Type;
    }

    fRadii[kUpperLeft_Corner].set(leftRad, topRad);
    fRadii[kUpperRight_Corner].set(rightRad, topRad);
    fRadii[kLowerRight_Corner].set(rightRad, bottomRad);
    fRadii[kLowerLeft_Corner].set(leftRad, bottomRad);

    SkDEBUGCODE(this->validate();)
}
    void generateGeometry(GrBatchTarget* batchTarget, const GrPipeline* pipeline) override {
        int instanceCount = fGeoData.count();

        SkMatrix invert;
        if (this->usesLocalCoords() && !this->viewMatrix().invert(&invert)) {
            SkDebugf("Could not invert viewmatrix\n");
            return;
        }

        uint32_t flags = 0;
        flags |= this->viewMatrix().isSimilarity() ? kSimilarity_DistanceFieldEffectFlag : 0;

        GrTextureParams params(SkShader::kRepeat_TileMode, GrTextureParams::kBilerp_FilterMode);

        // Setup GrGeometryProcessor
        GrBatchAtlas* atlas = fAtlas;
        SkAutoTUnref<GrGeometryProcessor> dfProcessor(
                GrDistanceFieldPathGeoProc::Create(this->color(),
                                                   this->viewMatrix(),
                                                   atlas->getTexture(),
                                                   params,
                                                   flags,
                                                   false));

        this->initDraw(batchTarget, dfProcessor, pipeline);

        static const int kVertsPerQuad = 4;
        static const int kIndicesPerQuad = 6;

        SkAutoTUnref<const GrIndexBuffer> indexBuffer(
            batchTarget->resourceProvider()->refQuadIndexBuffer());

        // allocate vertices
        size_t vertexStride = dfProcessor->getVertexStride();
        SkASSERT(vertexStride == 2 * sizeof(SkPoint));
        const GrVertexBuffer* vertexBuffer;
        int vertexCount = kVertsPerQuad * instanceCount;
        int firstVertex;

        void* vertices = batchTarget->vertexPool()->makeSpace(vertexStride,
                                                              vertexCount,
                                                              &vertexBuffer,
                                                              &firstVertex);

        if (!vertices || !indexBuffer) {
            SkDebugf("Could not allocate vertices\n");
            return;
        }

        // We may have to flush while uploading path data to the atlas, so we set up the draw here
        int maxInstancesPerDraw = indexBuffer->maxQuads();

        GrDrawTarget::DrawInfo drawInfo;
        drawInfo.setPrimitiveType(kTriangles_GrPrimitiveType);
        drawInfo.setStartVertex(0);
        drawInfo.setStartIndex(0);
        drawInfo.setVerticesPerInstance(kVertsPerQuad);
        drawInfo.setIndicesPerInstance(kIndicesPerQuad);
        drawInfo.adjustStartVertex(firstVertex);
        drawInfo.setVertexBuffer(vertexBuffer);
        drawInfo.setIndexBuffer(indexBuffer);

        int instancesToFlush = 0;
        for (int i = 0; i < instanceCount; i++) {
            Geometry& args = fGeoData[i];

            // get mip level
            SkScalar maxScale = this->viewMatrix().getMaxScale();
            const SkRect& bounds = args.fPath.getBounds();
            SkScalar maxDim = SkMaxScalar(bounds.width(), bounds.height());
            SkScalar size = maxScale * maxDim;
            uint32_t desiredDimension;
            if (size <= kSmallMIP) {
                desiredDimension = kSmallMIP;
            } else if (size <= kMediumMIP) {
                desiredDimension = kMediumMIP;
            } else {
                desiredDimension = kLargeMIP;
            }

            // check to see if path is cached
            // TODO: handle stroked vs. filled version of same path
            PathData::Key key = { args.fPath.getGenerationID(), desiredDimension };
            args.fPathData = fPathCache->find(key);
            if (NULL == args.fPathData || !atlas->hasID(args.fPathData->fID)) {
                // Remove the stale cache entry
                if (args.fPathData) {
                    fPathCache->remove(args.fPathData->fKey);
                    fPathList->remove(args.fPathData);
                    SkDELETE(args.fPathData);
                }
                SkScalar scale = desiredDimension/maxDim;
                args.fPathData = SkNEW(PathData);
                if (!this->addPathToAtlas(batchTarget,
                                          dfProcessor,
                                          pipeline,
                                          &drawInfo,
                                          &instancesToFlush,
                                          maxInstancesPerDraw,
                                          atlas,
                                          args.fPathData,
                                          args.fPath,
                                          args.fStroke,
                                          args.fAntiAlias,
                                          desiredDimension,
                                          scale)) {
                    SkDebugf("Can't rasterize path\n");
                    return;
                }
            }

            atlas->setLastUseToken(args.fPathData->fID, batchTarget->currentToken());

            // Now set vertices
            intptr_t offset = reinterpret_cast<intptr_t>(vertices);
            offset += i * kVertsPerQuad * vertexStride;
            SkPoint* positions = reinterpret_cast<SkPoint*>(offset);
            this->drawPath(batchTarget,
                           atlas,
                           pipeline,
                           dfProcessor,
                           positions,
                           vertexStride,
                           this->viewMatrix(),
                           args.fPath,
                           args.fPathData);
            instancesToFlush++;
        }

        this->flush(batchTarget, &drawInfo, instancesToFlush, maxInstancesPerDraw);
    }
bool SkMagnifierImageFilter::onFilterImage(Proxy*, const SkBitmap& src,
                                           const Context&, SkBitmap* dst,
                                           SkIPoint* offset) const {
    if ((src.colorType() != kN32_SkColorType) ||
        (fSrcRect.width() >= src.width()) ||
        (fSrcRect.height() >= src.height())) {
      return false;
    }

    SkAutoLockPixels alp(src);
    SkASSERT(src.getPixels());
    if (!src.getPixels() || src.width() <= 0 || src.height() <= 0) {
      return false;
    }

    if (!dst->tryAllocPixels(src.info())) {
        return false;
    }

    SkScalar inv_inset = fInset > 0 ? SkScalarInvert(fInset) : SK_Scalar1;

    SkScalar inv_x_zoom = fSrcRect.width() / src.width();
    SkScalar inv_y_zoom = fSrcRect.height() / src.height();

    SkColor* sptr = src.getAddr32(0, 0);
    SkColor* dptr = dst->getAddr32(0, 0);
    int width = src.width(), height = src.height();
    for (int y = 0; y < height; ++y) {
        for (int x = 0; x < width; ++x) {
            SkScalar x_dist = SkMin32(x, width - x - 1) * inv_inset;
            SkScalar y_dist = SkMin32(y, height - y - 1) * inv_inset;
            SkScalar weight = 0;

            static const SkScalar kScalar2 = SkScalar(2);

            // To create a smooth curve at the corners, we need to work on
            // a square twice the size of the inset.
            if (x_dist < kScalar2 && y_dist < kScalar2) {
                x_dist = kScalar2 - x_dist;
                y_dist = kScalar2 - y_dist;

                SkScalar dist = SkScalarSqrt(SkScalarSquare(x_dist) +
                                             SkScalarSquare(y_dist));
                dist = SkMaxScalar(kScalar2 - dist, 0);
                weight = SkMinScalar(SkScalarSquare(dist), SK_Scalar1);
            } else {
                SkScalar sqDist = SkMinScalar(SkScalarSquare(x_dist),
                                              SkScalarSquare(y_dist));
                weight = SkMinScalar(sqDist, SK_Scalar1);
            }

            SkScalar x_interp = SkScalarMul(weight, (fSrcRect.x() + x * inv_x_zoom)) +
                           (SK_Scalar1 - weight) * x;
            SkScalar y_interp = SkScalarMul(weight, (fSrcRect.y() + y * inv_y_zoom)) +
                           (SK_Scalar1 - weight) * y;

            int x_val = SkPin32(SkScalarFloorToInt(x_interp), 0, width - 1);
            int y_val = SkPin32(SkScalarFloorToInt(y_interp), 0, height - 1);

            *dptr = sptr[y_val * width + x_val];
            dptr++;
        }
    }
    return true;
}
    void onPrepareDraws(Target* target) const override {
        int instanceCount = fGeoData.count();

        SkMatrix invert;
        if (this->usesLocalCoords() && !this->viewMatrix().invert(&invert)) {
            SkDebugf("Could not invert viewmatrix\n");
            return;
        }

        const SkMatrix& ctm = this->viewMatrix();
        uint32_t flags = 0;
        flags |= ctm.isScaleTranslate() ? kScaleOnly_DistanceFieldEffectFlag : 0;
        flags |= ctm.isSimilarity() ? kSimilarity_DistanceFieldEffectFlag : 0;
        flags |= fGammaCorrect ? kGammaCorrect_DistanceFieldEffectFlag : 0;

        GrTextureParams params(SkShader::kRepeat_TileMode, GrTextureParams::kBilerp_FilterMode);

        FlushInfo flushInfo;

        // Setup GrGeometryProcessor
        GrBatchAtlas* atlas = fAtlas;
        flushInfo.fGeometryProcessor = GrDistanceFieldPathGeoProc::Make(this->color(),
                                                                        this->viewMatrix(),
                                                                        atlas->getTexture(),
                                                                        params,
                                                                        flags,
                                                                        this->usesLocalCoords());

        // allocate vertices
        size_t vertexStride = flushInfo.fGeometryProcessor->getVertexStride();
        SkASSERT(vertexStride == 2 * sizeof(SkPoint) + sizeof(GrColor));

        const GrBuffer* vertexBuffer;
        void* vertices = target->makeVertexSpace(vertexStride,
                                                 kVerticesPerQuad * instanceCount,
                                                 &vertexBuffer,
                                                 &flushInfo.fVertexOffset);
        flushInfo.fVertexBuffer.reset(SkRef(vertexBuffer));
        flushInfo.fIndexBuffer.reset(target->resourceProvider()->refQuadIndexBuffer());
        if (!vertices || !flushInfo.fIndexBuffer) {
            SkDebugf("Could not allocate vertices\n");
            return;
        }

        flushInfo.fInstancesToFlush = 0;
        // Pointer to the next set of vertices to write.
        intptr_t offset = reinterpret_cast<intptr_t>(vertices);
        for (int i = 0; i < instanceCount; i++) {
            const Geometry& args = fGeoData[i];

            // get mip level
            SkScalar maxScale = this->viewMatrix().getMaxScale();
            const SkRect& bounds = args.fShape.bounds();
            SkScalar maxDim = SkMaxScalar(bounds.width(), bounds.height());
            SkScalar size = maxScale * maxDim;
            uint32_t desiredDimension;
            if (size <= kSmallMIP) {
                desiredDimension = kSmallMIP;
            } else if (size <= kMediumMIP) {
                desiredDimension = kMediumMIP;
            } else {
                desiredDimension = kLargeMIP;
            }

            // check to see if path is cached
            ShapeData::Key key(args.fShape, desiredDimension);
            ShapeData* shapeData = fShapeCache->find(key);
            if (nullptr == shapeData || !atlas->hasID(shapeData->fID)) {
                // Remove the stale cache entry
                if (shapeData) {
                    fShapeCache->remove(shapeData->fKey);
                    fShapeList->remove(shapeData);
                    delete shapeData;
                }
                SkScalar scale = desiredDimension/maxDim;
                shapeData = new ShapeData;
                if (!this->addPathToAtlas(target,
                                          &flushInfo,
                                          atlas,
                                          shapeData,
                                          args.fShape,
                                          args.fAntiAlias,
                                          desiredDimension,
                                          scale)) {
                    delete shapeData;
                    SkDebugf("Can't rasterize path\n");
                    continue;
                }
            }

            atlas->setLastUseToken(shapeData->fID, target->nextDrawToken());

            this->writePathVertices(target,
                                    atlas,
                                    offset,
                                    args.fColor,
                                    vertexStride,
                                    this->viewMatrix(),
                                    shapeData);
            offset += kVerticesPerQuad * vertexStride;
            flushInfo.fInstancesToFlush++;
        }

        this->flush(target, &flushInfo);
    }
void SkDisplayMath::executeFunction(SkDisplayable* target, int index,
        SkTDArray<SkScriptValue>& parameters, SkDisplayTypes type,
        SkScriptValue* scriptValue) {
    if (scriptValue == NULL)
        return;
    SkASSERT(target == this);
    SkScriptValue* array = parameters.begin();
    SkScriptValue* end = parameters.end();
    SkScalar input = parameters[0].fOperand.fScalar;
    SkScalar scalarResult;
    switch (index) {
        case SK_FUNCTION(abs):
            scalarResult = SkScalarAbs(input);
            break;
        case SK_FUNCTION(acos):
            scalarResult = SkScalarACos(input);
            break;
        case SK_FUNCTION(asin):
            scalarResult = SkScalarASin(input);
            break;
        case SK_FUNCTION(atan):
            scalarResult = SkScalarATan2(input, SK_Scalar1);
            break;
        case SK_FUNCTION(atan2):
            scalarResult = SkScalarATan2(input, parameters[1].fOperand.fScalar);
            break;
        case SK_FUNCTION(ceil):
            scalarResult = SkIntToScalar(SkScalarCeil(input));
            break;
        case SK_FUNCTION(cos):
            scalarResult = SkScalarCos(input);
            break;
        case SK_FUNCTION(exp):
            scalarResult = SkScalarExp(input);
            break;
        case SK_FUNCTION(floor):
            scalarResult = SkIntToScalar(SkScalarFloor(input));
            break;
        case SK_FUNCTION(log):
            scalarResult = SkScalarLog(input);
            break;
        case SK_FUNCTION(max):
            scalarResult = -SK_ScalarMax;
            while (array < end) {
                scalarResult = SkMaxScalar(scalarResult, array->fOperand.fScalar);
                array++;
            }
            break;
        case SK_FUNCTION(min):
            scalarResult = SK_ScalarMax;
            while (array < end) {
                scalarResult = SkMinScalar(scalarResult, array->fOperand.fScalar);
                array++;
            }
            break;
        case SK_FUNCTION(pow):
            // not the greatest -- but use x^y = e^(y * ln(x))
            scalarResult = SkScalarLog(input);
            scalarResult = SkScalarMul(parameters[1].fOperand.fScalar, scalarResult);
            scalarResult = SkScalarExp(scalarResult);
            break;
        case SK_FUNCTION(random):
            scalarResult = fRandom.nextUScalar1();
            break;
        case SK_FUNCTION(round):
            scalarResult = SkIntToScalar(SkScalarRound(input));
            break;
        case SK_FUNCTION(sin):
            scalarResult = SkScalarSin(input);
            break;
        case SK_FUNCTION(sqrt): {
            SkASSERT(parameters.count() == 1);
            SkASSERT(type == SkType_Float);
            scalarResult = SkScalarSqrt(input);
            } break;
        case SK_FUNCTION(tan):
            scalarResult = SkScalarTan(input);
            break;
        default:
            SkASSERT(0);
            scalarResult = SK_ScalarNaN;
    }
    scriptValue->fOperand.fScalar = scalarResult;
    scriptValue->fType = SkType_Float;
}
    void onDraw(SkCanvas* canvas) override {
        static const char kText[] = "SKIA";
        static const int kTextLen = SK_ARRAY_COUNT(kText) - 1;
        static const int kPointSize = 55;

        SkTDArray<LabeledMatrix> matrices;
        matrices.append()->fMatrix.reset();
        matrices.top().fLabel = "Identity";
        matrices.append()->fMatrix.setScale(1.2f, 0.8f);
        matrices.top().fLabel = "Scale";
        matrices.append()->fMatrix.setRotate(10.f);
        matrices.top().fLabel = "Rotate";
        matrices.append()->fMatrix.reset();
        matrices.top().fMatrix.setPerspX(-0.0015f);
        matrices.top().fMatrix.setPerspY(+0.0015f);
        matrices.top().fLabel = "Persp";

        SkTDArray<LabeledMatrix> localMatrices;
        localMatrices.append()->fMatrix.reset();
        localMatrices.top().fLabel = "Identity";
        localMatrices.append()->fMatrix.setScale(2.5f, 0.2f);
        localMatrices.top().fLabel = "Scale";
        localMatrices.append()->fMatrix.setRotate(45.f);
        localMatrices.top().fLabel = "Rotate";
        localMatrices.append()->fMatrix.reset();
        localMatrices.top().fMatrix.setPerspX(-0.007f);
        localMatrices.top().fMatrix.setPerspY(+0.008f);
        localMatrices.top().fLabel = "Persp";

        static SkBitmap bmp;
        if (bmp.isNull()) {
            makebm(&bmp, kPointSize / 2, kPointSize / 2);
        }

        SkPaint fillPaint;
        fillPaint.setAntiAlias(true);
        sk_tool_utils::set_portable_typeface_always(&fillPaint);
        fillPaint.setTextSize(SkIntToScalar(kPointSize));
        fillPaint.setFilterQuality(kLow_SkFilterQuality);

        SkPaint outlinePaint;
        outlinePaint.setAntiAlias(true);
        sk_tool_utils::set_portable_typeface_always(&outlinePaint);
        outlinePaint.setTextSize(SkIntToScalar(kPointSize));
        outlinePaint.setStyle(SkPaint::kStroke_Style);
        outlinePaint.setStrokeWidth(0.f);

        SkScalar w = fillPaint.measureText(kText, kTextLen);
        static SkScalar kPadY = 0.5f * kPointSize;
        static SkScalar kPadX = 1.5f * kPointSize;

        SkPaint strokePaint(fillPaint);
        strokePaint.setStyle(SkPaint::kStroke_Style);
        strokePaint.setStrokeWidth(kPointSize * 0.1f);

        SkPaint labelPaint;
        labelPaint.setColor(0xff000000);
        labelPaint.setAntiAlias(true);
        sk_tool_utils::set_portable_typeface_always(&labelPaint);
        labelPaint.setTextSize(12.f);

        canvas->translate(15.f, 15.f);
        canvas->drawBitmap(bmp, 0, 0);
        canvas->translate(0, bmp.height() + labelPaint.getTextSize() + 15.f);

        static const char kLabelLabel[] = "localM / canvasM";
        canvas->drawText(kLabelLabel, strlen(kLabelLabel), 0, 0, labelPaint);
        canvas->translate(0, 15.f);

        canvas->save();
        SkScalar maxLabelW = 0;
        canvas->translate(0, kPadY / 2 + kPointSize);
        for (int lm = 0; lm < localMatrices.count(); ++lm) {
            canvas->drawText(matrices[lm].fLabel, strlen(matrices[lm].fLabel),
                             0, labelPaint.getTextSize() - 1, labelPaint);
            SkScalar labelW = labelPaint.measureText(matrices[lm].fLabel,
                              strlen(matrices[lm].fLabel));
            maxLabelW = SkMaxScalar(maxLabelW, labelW);
            canvas->translate(0.f, 2 * kPointSize + 2.5f * kPadY);
        }
        canvas->restore();

        canvas->translate(maxLabelW + kPadX / 2.f, 0.f);

        for (int s = 0; s < 2; ++s) {
            SkPaint& paint = s ? strokePaint : fillPaint;

            SkScalar columnH = 0;
            for (int m = 0; m < matrices.count(); ++m) {
                columnH = 0;
                canvas->save();
                canvas->drawText(matrices[m].fLabel, strlen(matrices[m].fLabel),
                                 0, labelPaint.getTextSize() - 1, labelPaint);
                canvas->translate(0, kPadY / 2 + kPointSize);
                columnH += kPadY / 2 + kPointSize;
                for (int lm = 0; lm < localMatrices.count(); ++lm) {
                    paint.setShader(
                        SkShader::CreateBitmapShader(bmp,
                                                     SkShader::kMirror_TileMode,
                                                     SkShader::kRepeat_TileMode,
                                                     &localMatrices[lm].fMatrix))->unref();

                    canvas->save();
                    canvas->concat(matrices[m].fMatrix);
                    canvas->drawText(kText, kTextLen, 0, 0, paint);
                    canvas->drawText(kText, kTextLen, 0, 0, outlinePaint);
                    canvas->restore();

                    SkPath path;
                    path.arcTo(SkRect::MakeXYWH(-0.1f * w, 0.f,
                                                1.2f * w, 2.f * kPointSize),
                               225.f, 359.f,
                               false);
                    path.close();

                    canvas->translate(0.f, kPointSize + kPadY);
                    columnH += kPointSize + kPadY;

                    canvas->save();
                    canvas->concat(matrices[m].fMatrix);
                    canvas->drawTextOnPath(kText, kTextLen, path, NULL, paint);
                    canvas->drawTextOnPath(kText, kTextLen, path, NULL, outlinePaint);
                    canvas->restore();
                    SkPaint stroke;
                    stroke.setStyle(SkPaint::kStroke_Style);
                    canvas->translate(0.f, kPointSize + kPadY);
                    columnH += kPointSize + kPadY;
                }
                canvas->restore();
                canvas->translate(w + kPadX, 0.f);
            }
            if (0 == s) {
                canvas->drawLine(0.f, -kPadY, 0.f, columnH + kPadY, outlinePaint);
                canvas->translate(kPadX / 2, 0.f);
                static const char kFillLabel[] = "Filled";
                static const char kStrokeLabel[] = "Stroked";
                SkScalar y = columnH + kPadY / 2;
                SkScalar fillX = -outlinePaint.measureText(kFillLabel, strlen(kFillLabel)) - kPadX;
                SkScalar strokeX = kPadX;
                canvas->drawText(kFillLabel, strlen(kFillLabel), fillX, y, labelPaint);
                canvas->drawText(kStrokeLabel, strlen(kStrokeLabel), strokeX, y, labelPaint);
            }
        }
    }
    void onPrepareDraws(Target* target) override {
        int instanceCount = fGeoData.count();

        SkMatrix invert;
        if (this->usesLocalCoords() && !this->viewMatrix().invert(&invert)) {
            SkDebugf("Could not invert viewmatrix\n");
            return;
        }

        uint32_t flags = 0;
        flags |= this->viewMatrix().isSimilarity() ? kSimilarity_DistanceFieldEffectFlag : 0;

        GrTextureParams params(SkShader::kRepeat_TileMode, GrTextureParams::kBilerp_FilterMode);

        // Setup GrGeometryProcessor
        GrBatchAtlas* atlas = fAtlas;
        SkAutoTUnref<GrGeometryProcessor> dfProcessor(
                GrDistanceFieldPathGeoProc::Create(this->color(),
                                                   this->viewMatrix(),
                                                   atlas->getTexture(),
                                                   params,
                                                   flags,
                                                   this->usesLocalCoords()));

        target->initDraw(dfProcessor, this->pipeline());

        FlushInfo flushInfo;

        // allocate vertices
        size_t vertexStride = dfProcessor->getVertexStride();
        SkASSERT(vertexStride == 2 * sizeof(SkPoint));

        const GrVertexBuffer* vertexBuffer;
        void* vertices = target->makeVertexSpace(vertexStride,
                                                 kVerticesPerQuad * instanceCount,
                                                 &vertexBuffer,
                                                 &flushInfo.fVertexOffset);
        flushInfo.fVertexBuffer.reset(SkRef(vertexBuffer));
        flushInfo.fIndexBuffer.reset(target->resourceProvider()->refQuadIndexBuffer());
        if (!vertices || !flushInfo.fIndexBuffer) {
            SkDebugf("Could not allocate vertices\n");
            return;
        }

        flushInfo.fInstancesToFlush = 0;
        for (int i = 0; i < instanceCount; i++) {
            Geometry& args = fGeoData[i];

            // get mip level
            SkScalar maxScale = this->viewMatrix().getMaxScale();
            const SkRect& bounds = args.fPath.getBounds();
            SkScalar maxDim = SkMaxScalar(bounds.width(), bounds.height());
            SkScalar size = maxScale * maxDim;
            uint32_t desiredDimension;
            if (size <= kSmallMIP) {
                desiredDimension = kSmallMIP;
            } else if (size <= kMediumMIP) {
                desiredDimension = kMediumMIP;
            } else {
                desiredDimension = kLargeMIP;
            }

            // check to see if path is cached
            // TODO: handle stroked vs. filled version of same path
            PathData::Key key = { args.fPath.getGenerationID(), desiredDimension };
            args.fPathData = fPathCache->find(key);
            if (NULL == args.fPathData || !atlas->hasID(args.fPathData->fID)) {
                // Remove the stale cache entry
                if (args.fPathData) {
                    fPathCache->remove(args.fPathData->fKey);
                    fPathList->remove(args.fPathData);
                    SkDELETE(args.fPathData);
                }
                SkScalar scale = desiredDimension/maxDim;
                args.fPathData = SkNEW(PathData);
                if (!this->addPathToAtlas(target,
                                          dfProcessor,
                                          this->pipeline(),
                                          &flushInfo,
                                          atlas,
                                          args.fPathData,
                                          args.fPath,
                                          args.fStroke,
                                          args.fAntiAlias,
                                          desiredDimension,
                                          scale)) {
                    SkDebugf("Can't rasterize path\n");
                    return;
                }
            }

            atlas->setLastUseToken(args.fPathData->fID, target->currentToken());

            // Now set vertices
            intptr_t offset = reinterpret_cast<intptr_t>(vertices);
            offset += i * kVerticesPerQuad * vertexStride;
            SkPoint* positions = reinterpret_cast<SkPoint*>(offset);
            this->writePathVertices(target,
                                    atlas,
                                    this->pipeline(),
                                    dfProcessor,
                                    positions,
                                    vertexStride,
                                    this->viewMatrix(),
                                    args.fPath,
                                    args.fPathData);
            flushInfo.fInstancesToFlush++;
        }

        this->flush(target, &flushInfo);
    }
Example #8
0
 // Add children
 void add(sk_sp<Control> control) override {
     SkASSERT(!fParent); // Validity of parent's relativeY and fHeight depends on immutability
     fControls.push_back(control);
     control->setParent(this, SkPoint::Make(0.0f, kSelectorHeight));
     fHeight = SkMaxScalar(fHeight, control->height()); // Setting height to max child height.
 }
bool SkXRayCrossesMonotonicCubic(const SkXRay& pt, const SkPoint cubic[4]) {
    // Find the minimum and maximum y of the extrema, which are the
    // first and last points since this cubic is monotonic
    SkScalar min_y = SkMinScalar(cubic[0].fY, cubic[3].fY);
    SkScalar max_y = SkMaxScalar(cubic[0].fY, cubic[3].fY);

    if (pt.fY == cubic[0].fY
        || pt.fY < min_y
        || pt.fY > max_y) {
        // The query line definitely does not cross the curve
        return false;
    }

    SkScalar min_x =
        SkMinScalar(
            SkMinScalar(
                SkMinScalar(cubic[0].fX, cubic[1].fX),
                cubic[2].fX),
            cubic[3].fX);
    if (pt.fX < min_x) {
        // The query line definitely crosses the curve
        return true;
    }

    SkScalar max_x =
        SkMaxScalar(
            SkMaxScalar(
                SkMaxScalar(cubic[0].fX, cubic[1].fX),
                cubic[2].fX),
            cubic[3].fX);
    if (pt.fX > max_x) {
        // The query line definitely does not cross the curve
        return false;
    }

    // Do a binary search to find the parameter value which makes y as
    // close as possible to the query point. See whether the query
    // line's origin is to the left of the associated x coordinate.

    // kMaxIter is chosen as the number of mantissa bits for a float,
    // since there's no way we are going to get more precision by
    // iterating more times than that.
    const int kMaxIter = 23;
    SkPoint eval;
    int iter = 0;
    SkScalar upper_t;
    SkScalar lower_t;
    // Need to invert direction of t parameter if cubic goes up
    // instead of down
    if (cubic[3].fY > cubic[0].fY) {
        upper_t = SK_Scalar1;
        lower_t = SkFloatToScalar(0);
    } else {
        upper_t = SkFloatToScalar(0);
        lower_t = SK_Scalar1;
    }
    do {
        SkScalar t = SkScalarAve(upper_t, lower_t);
        SkEvalCubicAt(cubic, t, &eval, NULL, NULL);
        if (pt.fY > eval.fY) {
            lower_t = t;
        } else {
            upper_t = t;
        }
    } while (++iter < kMaxIter
             && !SkScalarNearlyZero(eval.fY - pt.fY));
    if (pt.fX <= eval.fX) {
        return true;
    }
    return false;
}
sk_sp<SkSpecialImage> SkMagnifierImageFilter::onFilterImage(SkSpecialImage* source,
                                                            const Context& ctx,
                                                            SkIPoint* offset) const {
    SkIPoint inputOffset = SkIPoint::Make(0, 0);
    sk_sp<SkSpecialImage> input(this->filterInput(0, source, ctx, &inputOffset));
    if (!input) {
        return nullptr;
    }

    const SkIRect inputBounds = SkIRect::MakeXYWH(inputOffset.x(), inputOffset.y(),
                                                  input->width(), input->height());

    SkIRect bounds;
    if (!this->applyCropRect(ctx, inputBounds, &bounds)) {
        return nullptr;
    }

    SkScalar invInset = fInset > 0 ? SkScalarInvert(fInset) : SK_Scalar1;

    SkScalar invXZoom = fSrcRect.width() / bounds.width();
    SkScalar invYZoom = fSrcRect.height() / bounds.height();


#if SK_SUPPORT_GPU
    if (source->isTextureBacked()) {
        GrContext* context = source->getContext();

        sk_sp<GrTexture> inputTexture(input->asTextureRef(context));
        SkASSERT(inputTexture);

        offset->fX = bounds.left();
        offset->fY = bounds.top();
        bounds.offset(-inputOffset);

        SkScalar yOffset = inputTexture->origin() == kTopLeft_GrSurfaceOrigin 
            ? fSrcRect.y()
            : inputTexture->height() - 
                      fSrcRect.height() * inputTexture->height() / bounds.height() - fSrcRect.y();
        int boundsY = inputTexture->origin() == kTopLeft_GrSurfaceOrigin
            ? bounds.y()
            : inputTexture->height() - bounds.height();
        SkRect effectBounds = SkRect::MakeXYWH(
            SkIntToScalar(bounds.x()) / inputTexture->width(),
            SkIntToScalar(boundsY) / inputTexture->height(),
            SkIntToScalar(inputTexture->width()) / bounds.width(),
            SkIntToScalar(inputTexture->height()) / bounds.height());
        // SRGBTODO: Handle sRGB here
        sk_sp<GrFragmentProcessor> fp(GrMagnifierEffect::Create(
                                                        inputTexture.get(),
                                                        effectBounds,
                                                        fSrcRect.x() / inputTexture->width(),
                                                        yOffset / inputTexture->height(),
                                                        invXZoom,
                                                        invYZoom,
                                                        bounds.width() * invInset,
                                                        bounds.height() * invInset));
        if (!fp) {
            return nullptr;
        }

        return DrawWithFP(context, std::move(fp), bounds);
    }
#endif

    SkBitmap inputBM;

    if (!input->getROPixels(&inputBM)) {
        return nullptr;
    }

    if ((inputBM.colorType() != kN32_SkColorType) ||
        (fSrcRect.width() >= inputBM.width()) || (fSrcRect.height() >= inputBM.height())) {
        return nullptr;
    }

    SkAutoLockPixels alp(inputBM);
    SkASSERT(inputBM.getPixels());
    if (!inputBM.getPixels() || inputBM.width() <= 0 || inputBM.height() <= 0) {
        return nullptr;
    }

    const SkImageInfo info = SkImageInfo::MakeN32Premul(bounds.width(), bounds.height());

    SkBitmap dst;
    if (!dst.tryAllocPixels(info)) {
        return nullptr;
    }

    SkAutoLockPixels dstLock(dst);

    SkColor* dptr = dst.getAddr32(0, 0);
    int dstWidth = dst.width(), dstHeight = dst.height();
    for (int y = 0; y < dstHeight; ++y) {
        for (int x = 0; x < dstWidth; ++x) {
            SkScalar x_dist = SkMin32(x, dstWidth - x - 1) * invInset;
            SkScalar y_dist = SkMin32(y, dstHeight - y - 1) * invInset;
            SkScalar weight = 0;

            static const SkScalar kScalar2 = SkScalar(2);

            // To create a smooth curve at the corners, we need to work on
            // a square twice the size of the inset.
            if (x_dist < kScalar2 && y_dist < kScalar2) {
                x_dist = kScalar2 - x_dist;
                y_dist = kScalar2 - y_dist;

                SkScalar dist = SkScalarSqrt(SkScalarSquare(x_dist) +
                                             SkScalarSquare(y_dist));
                dist = SkMaxScalar(kScalar2 - dist, 0);
                weight = SkMinScalar(SkScalarSquare(dist), SK_Scalar1);
            } else {
                SkScalar sqDist = SkMinScalar(SkScalarSquare(x_dist),
                                              SkScalarSquare(y_dist));
                weight = SkMinScalar(sqDist, SK_Scalar1);
            }

            SkScalar x_interp = SkScalarMul(weight, (fSrcRect.x() + x * invXZoom)) +
                           (SK_Scalar1 - weight) * x;
            SkScalar y_interp = SkScalarMul(weight, (fSrcRect.y() + y * invYZoom)) +
                           (SK_Scalar1 - weight) * y;

            int x_val = SkTPin(bounds.x() + SkScalarFloorToInt(x_interp), 0, inputBM.width() - 1);
            int y_val = SkTPin(bounds.y() + SkScalarFloorToInt(y_interp), 0, inputBM.height() - 1);

            *dptr = *inputBM.getAddr32(x_val, y_val);
            dptr++;
        }
    }

    offset->fX = bounds.left();
    offset->fY = bounds.top();
    return SkSpecialImage::MakeFromRaster(SkIRect::MakeWH(bounds.width(), bounds.height()),
                                          dst);
}
static bool cheap_dist_exceeds_limit(const SkPoint& pt,
                                     SkScalar x, SkScalar y) {
    SkScalar dist = SkMaxScalar(SkScalarAbs(x - pt.fX), SkScalarAbs(y - pt.fY));
    // just made up the 1/2
    return dist > CHEAP_DIST_LIMIT;
}
Example #12
0
bool GrDashingEffect::DrawDashLine(const SkPoint pts[2], const GrPaint& paint,
                                   const GrStrokeInfo& strokeInfo, GrGpu* gpu,
                                   GrDrawTarget* target, const SkMatrix& vm) {

    if (!can_fast_path_dash(pts, strokeInfo, *target, vm)) {
        return false;
    }

    const SkPathEffect::DashInfo& info = strokeInfo.getDashInfo();

    SkPaint::Cap cap = strokeInfo.getStrokeRec().getCap();

    SkScalar srcStrokeWidth = strokeInfo.getStrokeRec().getWidth();

    // the phase should be normalized to be [0, sum of all intervals)
    SkASSERT(info.fPhase >= 0 && info.fPhase < info.fIntervals[0] + info.fIntervals[1]);

    SkScalar srcPhase = info.fPhase;

    // Rotate the src pts so they are aligned horizontally with pts[0].fX < pts[1].fX
    SkMatrix srcRotInv;
    SkPoint ptsRot[2];
    if (pts[0].fY != pts[1].fY || pts[0].fX > pts[1].fX) {
        SkMatrix rotMatrix;
        align_to_x_axis(pts, &rotMatrix, ptsRot);
        if(!rotMatrix.invert(&srcRotInv)) {
            GrPrintf("Failed to create invertible rotation matrix!\n");
            return false;
        }
    } else {
        srcRotInv.reset();
        memcpy(ptsRot, pts, 2 * sizeof(SkPoint));
    }

    bool useAA = paint.isAntiAlias();

    // Scale corrections of intervals and stroke from view matrix
    SkScalar parallelScale;
    SkScalar perpScale;
    calc_dash_scaling(&parallelScale, &perpScale, vm, ptsRot);

    bool hasCap = SkPaint::kButt_Cap != cap && 0 != srcStrokeWidth;

    // We always want to at least stroke out half a pixel on each side in device space
    // so 0.5f / perpScale gives us this min in src space
    SkScalar halfSrcStroke = SkMaxScalar(srcStrokeWidth * 0.5f, 0.5f / perpScale);

    SkScalar strokeAdj;
    if (!hasCap) {
        strokeAdj = 0.f;
    } else {
        strokeAdj = halfSrcStroke;
    }

    SkScalar startAdj = 0;

    SkMatrix combinedMatrix = srcRotInv;
    combinedMatrix.postConcat(vm);

    bool lineDone = false;
    SkRect startRect;
    bool hasStartRect = false;
    // If we are using AA, check to see if we are drawing a partial dash at the start. If so
    // draw it separately here and adjust our start point accordingly
    if (useAA) {
        if (srcPhase > 0 && srcPhase < info.fIntervals[0]) {
            SkPoint startPts[2];
            startPts[0] = ptsRot[0];
            startPts[1].fY = startPts[0].fY;
            startPts[1].fX = SkMinScalar(startPts[0].fX + info.fIntervals[0] - srcPhase,
                                         ptsRot[1].fX);
            startRect.set(startPts, 2);
            startRect.outset(strokeAdj, halfSrcStroke);

            hasStartRect = true;
            startAdj = info.fIntervals[0] + info.fIntervals[1] - srcPhase;
        }
    }

    // adjustments for start and end of bounding rect so we only draw dash intervals
    // contained in the original line segment.
    startAdj += calc_start_adjustment(info);
    if (startAdj != 0) {
        ptsRot[0].fX += startAdj;
        srcPhase = 0;
    }
    SkScalar endingInterval = 0;
    SkScalar endAdj = calc_end_adjustment(info, ptsRot, srcPhase, &endingInterval);
    ptsRot[1].fX -= endAdj;
    if (ptsRot[0].fX >= ptsRot[1].fX) {
        lineDone = true;
    }

    SkRect endRect;
    bool hasEndRect = false;
    // If we are using AA, check to see if we are drawing a partial dash at then end. If so
    // draw it separately here and adjust our end point accordingly
    if (useAA && !lineDone) {
        // If we adjusted the end then we will not be drawing a partial dash at the end.
        // If we didn't adjust the end point then we just need to make sure the ending
        // dash isn't a full dash
        if (0 == endAdj && endingInterval != info.fIntervals[0]) {
            SkPoint endPts[2];
            endPts[1] = ptsRot[1];
            endPts[0].fY = endPts[1].fY;
            endPts[0].fX = endPts[1].fX - endingInterval;

            endRect.set(endPts, 2);
            endRect.outset(strokeAdj, halfSrcStroke);

            hasEndRect = true;
            endAdj = endingInterval + info.fIntervals[1];

            ptsRot[1].fX -= endAdj;
            if (ptsRot[0].fX >= ptsRot[1].fX) {
                lineDone = true;
            }
        }
    }

    if (startAdj != 0) {
        srcPhase = 0;
    }

    // Change the dashing info from src space into device space
    SkScalar devIntervals[2];
    devIntervals[0] = info.fIntervals[0] * parallelScale;
    devIntervals[1] = info.fIntervals[1] * parallelScale;
    SkScalar devPhase = srcPhase * parallelScale;
    SkScalar strokeWidth = srcStrokeWidth * perpScale;

    if ((strokeWidth < 1.f && !useAA) || 0.f == strokeWidth) {
        strokeWidth = 1.f;
    }

    SkScalar halfDevStroke = strokeWidth * 0.5f;

    if (SkPaint::kSquare_Cap == cap && 0 != srcStrokeWidth) {
        // add cap to on interveal and remove from off interval
        devIntervals[0] += strokeWidth;
        devIntervals[1] -= strokeWidth;
    }
    SkScalar startOffset = devIntervals[1] * 0.5f + devPhase;

    SkScalar bloatX = useAA ? 0.5f / parallelScale : 0.f;
    SkScalar bloatY = useAA ? 0.5f / perpScale : 0.f;

    SkScalar devBloat = useAA ? 0.5f : 0.f;

    GrDrawState* drawState = target->drawState();
    if (devIntervals[1] <= 0.f && useAA) {
        // Case when we end up drawing a solid AA rect
        // Reset the start rect to draw this single solid rect
        // but it requires to upload a new intervals uniform so we can mimic
        // one giant dash
        ptsRot[0].fX -= hasStartRect ? startAdj : 0;
        ptsRot[1].fX += hasEndRect ? endAdj : 0;
        startRect.set(ptsRot, 2);
        startRect.outset(strokeAdj, halfSrcStroke);
        hasStartRect = true;
        hasEndRect = false;
        lineDone = true;

        SkPoint devicePts[2];
        vm.mapPoints(devicePts, ptsRot, 2);
        SkScalar lineLength = SkPoint::Distance(devicePts[0], devicePts[1]);
        if (hasCap) {
            lineLength += 2.f * halfDevStroke;
        }
        devIntervals[0] = lineLength;
    }
    if (devIntervals[1] > 0.f || useAA) {
        SkPathEffect::DashInfo devInfo;
        devInfo.fPhase = devPhase;
        devInfo.fCount = 2;
        devInfo.fIntervals = devIntervals;
        GrEffectEdgeType edgeType= useAA ? kFillAA_GrEffectEdgeType :
            kFillBW_GrEffectEdgeType;
        bool isRoundCap = SkPaint::kRound_Cap == cap;
        GrDashingEffect::DashCap capType = isRoundCap ? GrDashingEffect::kRound_DashCap :
                                                        GrDashingEffect::kNonRound_DashCap;
        drawState->addCoverageEffect(
            GrDashingEffect::Create(edgeType, devInfo, strokeWidth, capType), 1)->unref();
    }

    // Set up the vertex data for the line and start/end dashes
    drawState->setVertexAttribs<gDashLineVertexAttribs>(SK_ARRAY_COUNT(gDashLineVertexAttribs));

    int totalRectCnt = 0;

    totalRectCnt += !lineDone ? 1 : 0;
    totalRectCnt += hasStartRect ? 1 : 0;
    totalRectCnt += hasEndRect ? 1 : 0;

    GrDrawTarget::AutoReleaseGeometry geo(target, totalRectCnt * 4, 0);
    if (!geo.succeeded()) {
        GrPrintf("Failed to get space for vertices!\n");
        return false;
    }

    DashLineVertex* verts = reinterpret_cast<DashLineVertex*>(geo.vertices());

    int curVIdx = 0;

    if (SkPaint::kRound_Cap == cap && 0 != srcStrokeWidth) {
        // need to adjust this for round caps to correctly set the dashPos attrib on vertices
        startOffset -= halfDevStroke;
    }

    // Draw interior part of dashed line
    if (!lineDone) {
        SkPoint devicePts[2];
        vm.mapPoints(devicePts, ptsRot, 2);
        SkScalar lineLength = SkPoint::Distance(devicePts[0], devicePts[1]);
        if (hasCap) {
            lineLength += 2.f * halfDevStroke;
        }

        SkRect bounds;
        bounds.set(ptsRot[0].fX, ptsRot[0].fY, ptsRot[1].fX, ptsRot[1].fY);
        bounds.outset(bloatX + strokeAdj, bloatY + halfSrcStroke);
        setup_dashed_rect(bounds, verts, curVIdx, combinedMatrix, startOffset, devBloat,
                          lineLength, halfDevStroke);
        curVIdx += 4;
    }

    if (hasStartRect) {
        SkASSERT(useAA);  // so that we know bloatX and bloatY have been set
        startRect.outset(bloatX, bloatY);
        setup_dashed_rect(startRect, verts, curVIdx, combinedMatrix, startOffset, devBloat,
                          devIntervals[0], halfDevStroke);
        curVIdx += 4;
    }

    if (hasEndRect) {
        SkASSERT(useAA);  // so that we know bloatX and bloatY have been set
        endRect.outset(bloatX, bloatY);
        setup_dashed_rect(endRect, verts, curVIdx, combinedMatrix, startOffset, devBloat,
                          devIntervals[0], halfDevStroke);
    }

    target->setIndexSourceToBuffer(gpu->getContext()->getQuadIndexBuffer());
    target->drawIndexedInstances(kTriangles_GrPrimitiveType, totalRectCnt, 4, 6);
    target->resetIndexSource();
    return true;
}
Example #13
0
static sk_sp<SkImage> makebm(SkCanvas* origCanvas, SkBitmap* resultBM, int w, int h) {
    SkImageInfo info = SkImageInfo::MakeN32Premul(w, h);
    
    SkAutoTUnref<SkSurface> surface(origCanvas->newSurface(info));
    if (nullptr == surface) {
        // picture canvas will return null, so fall-back to raster
        surface.reset(SkSurface::NewRaster(info));
    }

    SkCanvas* canvas = surface->getCanvas();

    canvas->clear(SK_ColorTRANSPARENT);

    SkScalar wScalar = SkIntToScalar(w);
    SkScalar hScalar = SkIntToScalar(h);

    SkPoint     pt = { wScalar / 2, hScalar / 2 };

    SkScalar    radius = 4 * SkMaxScalar(wScalar, hScalar);

    SkColor     colors[] = { SK_ColorRED, SK_ColorYELLOW,
                             SK_ColorGREEN, SK_ColorMAGENTA,
                             SK_ColorBLUE, SK_ColorCYAN,
                             SK_ColorRED};

    SkScalar    pos[] = {0,
                         SK_Scalar1 / 6,
                         2 * SK_Scalar1 / 6,
                         3 * SK_Scalar1 / 6,
                         4 * SK_Scalar1 / 6,
                         5 * SK_Scalar1 / 6,
                         SK_Scalar1};

    SkPaint     paint;
    SkRect rect = SkRect::MakeWH(wScalar, hScalar);
    SkMatrix mat = SkMatrix::I();
    for (int i = 0; i < 4; ++i) {
        paint.setShader(SkGradientShader::MakeRadial(
                        pt, radius,
                        colors, pos,
                        SK_ARRAY_COUNT(colors),
                        SkShader::kRepeat_TileMode,
                        0, &mat));
        canvas->drawRect(rect, paint);
        rect.inset(wScalar / 8, hScalar / 8);
        mat.postScale(SK_Scalar1 / 4, SK_Scalar1 / 4);
    }

    auto image = surface->makeImageSnapshot();

    SkBitmap tempBM;

#if SK_SUPPORT_GPU
    if (GrTexture* texture = as_IB(image)->peekTexture()) {
        GrWrapTextureInBitmap(texture, image->width(), image->height(), image->isOpaque(), &tempBM);
    } else 
#endif
    {
        image->asLegacyBitmap(&tempBM, SkImage::kRO_LegacyBitmapMode);
    }

    // Let backends know we won't change this, so they don't have to deep copy it defensively.
    tempBM.setImmutable();
    *resultBM = tempBM;

    return image;
}
Example #14
0
SkScalerContext_FreeType::SkScalerContext_FreeType(const SkDescriptor* desc)
        : SkScalerContext(desc) {
    SkAutoMutexAcquire  ac(gFTMutex);

    if (gFTCount == 0) {
        if (!InitFreetype()) {
            sk_throw();
        }
    }
    ++gFTCount;

    // load the font file
    fFTSize = NULL;
    fFace = NULL;
    fFaceRec = ref_ft_face(fRec.fFontID);
    if (NULL == fFaceRec) {
        return;
    }
    fFace = fFaceRec->fFace;

    // compute our factors from the record

    SkMatrix    m;

    fRec.getSingleMatrix(&m);

#ifdef DUMP_STRIKE_CREATION
    SkString     keyString;
    SkFontHost::GetDescriptorKeyString(desc, &keyString);
    printf("========== strike [%g %g %g] [%g %g %g %g] hints %d format %d %s\n", SkScalarToFloat(fRec.fTextSize),
           SkScalarToFloat(fRec.fPreScaleX), SkScalarToFloat(fRec.fPreSkewX),
           SkScalarToFloat(fRec.fPost2x2[0][0]), SkScalarToFloat(fRec.fPost2x2[0][1]),
           SkScalarToFloat(fRec.fPost2x2[1][0]), SkScalarToFloat(fRec.fPost2x2[1][1]),
           fRec.getHinting(), fRec.fMaskFormat, keyString.c_str());
#endif

    //  now compute our scale factors
    SkScalar    sx = m.getScaleX();
    SkScalar    sy = m.getScaleY();

    if (m.getSkewX() || m.getSkewY() || sx < 0 || sy < 0) {
        // sort of give up on hinting
        sx = SkMaxScalar(SkScalarAbs(sx), SkScalarAbs(m.getSkewX()));
        sy = SkMaxScalar(SkScalarAbs(m.getSkewY()), SkScalarAbs(sy));
        sx = sy = SkScalarAve(sx, sy);

        SkScalar inv = SkScalarInvert(sx);

        // flip the skew elements to go from our Y-down system to FreeType's
        fMatrix22.xx = SkScalarToFixed(SkScalarMul(m.getScaleX(), inv));
        fMatrix22.xy = -SkScalarToFixed(SkScalarMul(m.getSkewX(), inv));
        fMatrix22.yx = -SkScalarToFixed(SkScalarMul(m.getSkewY(), inv));
        fMatrix22.yy = SkScalarToFixed(SkScalarMul(m.getScaleY(), inv));
    } else {
        fMatrix22.xx = fMatrix22.yy = SK_Fixed1;
        fMatrix22.xy = fMatrix22.yx = 0;
    }

    fScaleX = SkScalarToFixed(sx);
    fScaleY = SkScalarToFixed(sy);

    // compute the flags we send to Load_Glyph
    {
        FT_Int32 loadFlags = FT_LOAD_DEFAULT;

        if (SkMask::kBW_Format == fRec.fMaskFormat) {
            // See http://code.google.com/p/chromium/issues/detail?id=43252#c24
            loadFlags = FT_LOAD_TARGET_MONO;
            if (fRec.getHinting() == SkPaint::kNo_Hinting)
                loadFlags = FT_LOAD_NO_HINTING;
        } else {
            switch (fRec.getHinting()) {
            case SkPaint::kNo_Hinting:
                loadFlags = FT_LOAD_NO_HINTING;
                break;
            case SkPaint::kSlight_Hinting:
                loadFlags = FT_LOAD_TARGET_LIGHT;  // This implies FORCE_AUTOHINT
                break;
            case SkPaint::kNormal_Hinting:
                loadFlags = FT_LOAD_TARGET_NORMAL;
                break;
            case SkPaint::kFull_Hinting:
                loadFlags = FT_LOAD_TARGET_NORMAL;
                if (SkMask::kHorizontalLCD_Format == fRec.fMaskFormat)
                    loadFlags = FT_LOAD_TARGET_LCD;
                else if (SkMask::kVerticalLCD_Format == fRec.fMaskFormat)
                    loadFlags = FT_LOAD_TARGET_LCD_V;
                break;
            default:
                SkDebugf("---------- UNKNOWN hinting %d\n", fRec.getHinting());
                break;
            }
        }

        if ((fRec.fFlags & SkScalerContext::kEmbeddedBitmapText_Flag) == 0)
            loadFlags |= FT_LOAD_NO_BITMAP;

        fLoadGlyphFlags = loadFlags;
    }

    // now create the FT_Size

    {
        FT_Error    err;

        err = FT_New_Size(fFace, &fFTSize);
        if (err != 0) {
            SkDEBUGF(("SkScalerContext_FreeType::FT_New_Size(%x): FT_Set_Char_Size(0x%x, 0x%x) returned 0x%x\n",
                        fFaceRec->fFontID, fScaleX, fScaleY, err));
            fFace = NULL;
            return;
        }

        err = FT_Activate_Size(fFTSize);
        if (err != 0) {
            SkDEBUGF(("SkScalerContext_FreeType::FT_Activate_Size(%x, 0x%x, 0x%x) returned 0x%x\n",
                        fFaceRec->fFontID, fScaleX, fScaleY, err));
            fFTSize = NULL;
        }

        err = FT_Set_Char_Size( fFace,
                                SkFixedToFDot6(fScaleX), SkFixedToFDot6(fScaleY),
                                72, 72);
        if (err != 0) {
            SkDEBUGF(("SkScalerContext_FreeType::FT_Set_Char_Size(%x, 0x%x, 0x%x) returned 0x%x\n",
                        fFaceRec->fFontID, fScaleX, fScaleY, err));
            fFace = NULL;
            return;
        }

        FT_Set_Transform( fFace, &fMatrix22, NULL);
    }
}
Example #15
0
SkScalerContext_FreeType::SkScalerContext_FreeType(const SkDescriptor* desc)
        : SkScalerContext(desc), fFTSize(NULL) {
    SkAutoMutexAcquire  ac(gFTMutex);

    FT_Error    err;

    if (gFTCount == 0) {
        err = FT_Init_FreeType(&gFTLibrary);
//        SkDEBUGF(("FT_Init_FreeType returned %d\n", err));
        SkASSERT(err == 0);
    }
    ++gFTCount;

    // load the font file
    fFaceRec = ref_ft_face(fRec.fFontID);
    fFace = fFaceRec ? fFaceRec->fFace : NULL;

    // compute our factors from the record

    SkMatrix    m;

    fRec.getSingleMatrix(&m);

#ifdef DUMP_STRIKE_CREATION
    SkString     keyString;
    SkFontHost::GetDescriptorKeyString(desc, &keyString);
    printf("========== strike [%g %g %g] [%g %g %g %g] hints %d format %d %s\n", SkScalarToFloat(fRec.fTextSize),
           SkScalarToFloat(fRec.fPreScaleX), SkScalarToFloat(fRec.fPreSkewX),
           SkScalarToFloat(fRec.fPost2x2[0][0]), SkScalarToFloat(fRec.fPost2x2[0][1]),
           SkScalarToFloat(fRec.fPost2x2[1][0]), SkScalarToFloat(fRec.fPost2x2[1][1]),
           fRec.fHints, fRec.fMaskFormat, keyString.c_str());
#endif

    //  now compute our scale factors
    SkScalar    sx = m.getScaleX();
    SkScalar    sy = m.getScaleY();

    if (m.getSkewX() || m.getSkewY() || sx < 0 || sy < 0) {
        // sort of give up on hinting
        sx = SkMaxScalar(SkScalarAbs(sx), SkScalarAbs(m.getSkewX()));
        sy = SkMaxScalar(SkScalarAbs(m.getSkewY()), SkScalarAbs(sy));
        sx = sy = SkScalarAve(sx, sy);

        SkScalar inv = SkScalarInvert(sx);

        // flip the skew elements to go from our Y-down system to FreeType's
        fMatrix22.xx = SkScalarToFixed(SkScalarMul(m.getScaleX(), inv));
        fMatrix22.xy = -SkScalarToFixed(SkScalarMul(m.getSkewX(), inv));
        fMatrix22.yx = -SkScalarToFixed(SkScalarMul(m.getSkewY(), inv));
        fMatrix22.yy = SkScalarToFixed(SkScalarMul(m.getScaleY(), inv));
    } else {
        fMatrix22.xx = fMatrix22.yy = SK_Fixed1;
        fMatrix22.xy = fMatrix22.yx = 0;
    }

    fScaleX = SkScalarToFixed(sx);
    fScaleY = SkScalarToFixed(sy);

    // compute the flags we send to Load_Glyph
    {
        uint32_t flags = FT_LOAD_DEFAULT;
        uint32_t render_flags = FT_LOAD_TARGET_NORMAL;

        // we force autohinting at the moment

        switch (fRec.fHints) {
        case kNo_Hints:
            flags |= FT_LOAD_NO_HINTING;
            break;
        case kSubpixel_Hints:
            flags |= FT_LOAD_FORCE_AUTOHINT;
            render_flags = FT_LOAD_TARGET_LIGHT;
            break;
        case kNormal_Hints:
            flags |= FT_LOAD_FORCE_AUTOHINT;
#ifdef ANDROID
            /*  Switch to light hinting (vertical only) to address some chars
                that behaved poorly with NORMAL. In the future we could consider
                making this choice exposed at runtime to the caller.
            */
            render_flags = FT_LOAD_TARGET_LIGHT;
#endif
            break;
        }

        if (SkMask::kBW_Format == fRec.fMaskFormat)
            render_flags = FT_LOAD_TARGET_MONO;
        else if (SkMask::kLCD_Format == fRec.fMaskFormat)
            render_flags = FT_LOAD_TARGET_LCD;

        fLoadGlyphFlags = flags | render_flags;
    }

    // now create the FT_Size

    {
        FT_Error    err;

        err = FT_New_Size(fFace, &fFTSize);
        if (err != 0) {
            SkDEBUGF(("SkScalerContext_FreeType::FT_New_Size(%x): FT_Set_Char_Size(0x%x, 0x%x) returned 0x%x\n",
                        fFaceRec->fFontID, fScaleX, fScaleY, err));
            fFace = NULL;
            return;
        }

        err = FT_Activate_Size(fFTSize);
        if (err != 0) {
            SkDEBUGF(("SkScalerContext_FreeType::FT_Activate_Size(%x, 0x%x, 0x%x) returned 0x%x\n",
                        fFaceRec->fFontID, fScaleX, fScaleY, err));
            fFTSize = NULL;
        }

        err = FT_Set_Char_Size( fFace,
                                SkFixedToFDot6(fScaleX), SkFixedToFDot6(fScaleY),
                                72, 72);
        if (err != 0) {
            SkDEBUGF(("SkScalerContext_FreeType::FT_Set_Char_Size(%x, 0x%x, 0x%x) returned 0x%x\n",
                        fFaceRec->fFontID, fScaleX, fScaleY, err));
            fFace = NULL;
            return;
        }

        FT_Set_Transform( fFace, &fMatrix22, NULL);
    }
}
Example #16
0
bool SkPathMeasure::cheap_dist_exceeds_limit(const SkPoint& pt,
                                     SkScalar x, SkScalar y) {
    SkScalar dist = SkMaxScalar(SkScalarAbs(x - pt.fX), SkScalarAbs(y - pt.fY));
    // just made up the 1/2
    return dist > fTolerance;
}