Exemplo n.º 1
0
// static
SkPDFObject* SkPDFShader::GetPDFShader(const SkShader& shader,
                                       const SkMatrix& matrix,
                                       const SkIRect& surfaceBBox) {
    SkPDFObject* result;
    SkAutoMutexAcquire lock(CanonicalShadersMutex());
    SkAutoTDelete<State> shaderState(new State(shader, matrix, surfaceBBox));

    ShaderCanonicalEntry entry(NULL, shaderState.get());
    int index = CanonicalShaders().find(entry);
    if (index >= 0) {
        result = CanonicalShaders()[index].fPDFShader;
        result->ref();
        return result;
    }
    // The PDFShader takes ownership of the shaderSate.
    if (shaderState.get()->fType == SkShader::kNone_GradientType) {
        result = new SkPDFImageShader(shaderState.detach());
    } else {
        SkPDFFunctionShader* functionShader =
            new SkPDFFunctionShader(shaderState.detach());
        if (!functionShader->isValid()) {
            delete functionShader;
            return NULL;
        }
        result = functionShader;
    }
    entry.fPDFShader = result;
    CanonicalShaders().push(entry);
    return result;  // return the reference that came from new.
}
Exemplo n.º 2
0
// static
SkPDFObject* SkPDFShader::GetPDFShaderByState(State* inState) {
    SkPDFObject* result;

    SkAutoTDelete<State> shaderState(inState);
    if (shaderState.get()->fType == SkShader::kNone_GradientType &&
            shaderState.get()->fImage.isNull()) {
        // TODO(vandebo) This drops SKComposeShader on the floor.  We could
        // handle compose shader by pulling things up to a layer, drawing with
        // the first shader, applying the xfer mode and drawing again with the
        // second shader, then applying the layer to the original drawing.
        return NULL;
    }

    ShaderCanonicalEntry entry(NULL, shaderState.get());
    int index = CanonicalShaders().find(entry);
    if (index >= 0) {
        result = CanonicalShaders()[index].fPDFShader;
        result->ref();
        return result;
    }

    bool valid = false;
    // The PDFShader takes ownership of the shaderSate.
    if (shaderState.get()->fType == SkShader::kNone_GradientType) {
        SkPDFImageShader* imageShader =
            new SkPDFImageShader(shaderState.detach());
        valid = imageShader->isValid();
        result = imageShader;
    } else {
        if (shaderState.get()->GradientHasAlpha()) {
            SkPDFAlphaFunctionShader* gradientShader =
                SkNEW_ARGS(SkPDFAlphaFunctionShader, (shaderState.detach()));
            valid = gradientShader->isValid();
            result = gradientShader;
        } else {
            SkPDFFunctionShader* functionShader =
                SkNEW_ARGS(SkPDFFunctionShader, (shaderState.detach()));
            valid = functionShader->isValid();
            result = functionShader;
        }
    }
    if (!valid) {
        delete result;
        return NULL;
    }
    entry.fPDFShader = result;
    CanonicalShaders().push(entry);
    return result;  // return the reference that came from new.
}
Exemplo n.º 3
0
SkPDFFunctionShader* SkPDFFunctionShader::Create(
        SkPDFCanon* canon, SkAutoTDelete<SkPDFShader::State>* autoState) {
    const SkPDFShader::State& state = **autoState;

    SkString (*codeFunction)(const SkShader::GradientInfo& info,
                             const SkMatrix& perspectiveRemover) = NULL;
    SkPoint transformPoints[2];

    // Depending on the type of the gradient, we want to transform the
    // coordinate space in different ways.
    const SkShader::GradientInfo* info = &state.fInfo;
    transformPoints[0] = info->fPoint[0];
    transformPoints[1] = info->fPoint[1];
    switch (state.fType) {
        case SkShader::kLinear_GradientType:
            codeFunction = &linearCode;
            break;
        case SkShader::kRadial_GradientType:
            transformPoints[1] = transformPoints[0];
            transformPoints[1].fX += info->fRadius[0];
            codeFunction = &radialCode;
            break;
        case SkShader::kRadial2_GradientType: {
            // Bail out if the radii are the same.
            if (info->fRadius[0] == info->fRadius[1]) {
                return NULL;
            }
            transformPoints[1] = transformPoints[0];
            SkScalar dr = info->fRadius[1] - info->fRadius[0];
            transformPoints[1].fX += dr;
            codeFunction = &twoPointRadialCode;
            break;
        }
        case SkShader::kConical_GradientType: {
            transformPoints[1] = transformPoints[0];
            transformPoints[1].fX += SK_Scalar1;
            codeFunction = &twoPointConicalCode;
            break;
        }
        case SkShader::kSweep_GradientType:
            transformPoints[1] = transformPoints[0];
            transformPoints[1].fX += SK_Scalar1;
            codeFunction = &sweepCode;
            break;
        case SkShader::kColor_GradientType:
        case SkShader::kNone_GradientType:
        default:
            return NULL;
    }

    // Move any scaling (assuming a unit gradient) or translation
    // (and rotation for linear gradient), of the final gradient from
    // info->fPoints to the matrix (updating bbox appropriately).  Now
    // the gradient can be drawn on on the unit segment.
    SkMatrix mapperMatrix;
    unitToPointsMatrix(transformPoints, &mapperMatrix);

    SkMatrix finalMatrix = state.fCanvasTransform;
    finalMatrix.preConcat(state.fShaderTransform);
    finalMatrix.preConcat(mapperMatrix);

    // Preserves as much as posible in the final matrix, and only removes
    // the perspective. The inverse of the perspective is stored in
    // perspectiveInverseOnly matrix and has 3 useful numbers
    // (p0, p1, p2), while everything else is either 0 or 1.
    // In this way the shader will handle it eficiently, with minimal code.
    SkMatrix perspectiveInverseOnly = SkMatrix::I();
    if (finalMatrix.hasPerspective()) {
        if (!split_perspective(finalMatrix,
                               &finalMatrix, &perspectiveInverseOnly)) {
            return NULL;
        }
    }

    SkRect bbox;
    bbox.set(state.fBBox);
    if (!inverse_transform_bbox(finalMatrix, &bbox)) {
        return NULL;
    }

    SkAutoTUnref<SkPDFArray> domain(new SkPDFArray);
    domain->reserve(4);
    domain->appendScalar(bbox.fLeft);
    domain->appendScalar(bbox.fRight);
    domain->appendScalar(bbox.fTop);
    domain->appendScalar(bbox.fBottom);

    SkString functionCode;
    // The two point radial gradient further references
    // state.fInfo
    // in translating from x, y coordinates to the t parameter. So, we have
    // to transform the points and radii according to the calculated matrix.
    if (state.fType == SkShader::kRadial2_GradientType) {
        SkShader::GradientInfo twoPointRadialInfo = *info;
        SkMatrix inverseMapperMatrix;
        if (!mapperMatrix.invert(&inverseMapperMatrix)) {
            return NULL;
        }
        inverseMapperMatrix.mapPoints(twoPointRadialInfo.fPoint, 2);
        twoPointRadialInfo.fRadius[0] =
            inverseMapperMatrix.mapRadius(info->fRadius[0]);
        twoPointRadialInfo.fRadius[1] =
            inverseMapperMatrix.mapRadius(info->fRadius[1]);
        functionCode = codeFunction(twoPointRadialInfo, perspectiveInverseOnly);
    } else {
        functionCode = codeFunction(*info, perspectiveInverseOnly);
    }

    SkAutoTUnref<SkPDFDict> pdfShader(new SkPDFDict);
    pdfShader->insertInt("ShadingType", 1);
    pdfShader->insertName("ColorSpace", "DeviceRGB");
    pdfShader->insert("Domain", domain.get());

    SkAutoTUnref<SkPDFStream> function(
            make_ps_function(functionCode, domain.get()));
    pdfShader->insert("Function", new SkPDFObjRef(function))->unref();

    SkAutoTUnref<SkPDFArray> matrixArray(
            SkPDFUtils::MatrixToArray(finalMatrix));

    SkPDFFunctionShader* pdfFunctionShader =
            SkNEW_ARGS(SkPDFFunctionShader, (autoState->detach()));

    pdfFunctionShader->insertInt("PatternType", 2);
    pdfFunctionShader->insert("Matrix", matrixArray.get());
    pdfFunctionShader->insert("Shading", pdfShader.get());

    canon->addFunctionShader(pdfFunctionShader);
    return pdfFunctionShader;
}