Exemplo n.º 1
0
static SkScalar nextScalarRange(SkRandom& rand, SkScalar min, SkScalar max) {
    return min + SkScalarMul(rand.nextUScalar1(), max - min);
}
Exemplo n.º 2
0
static void scale_rect(SkRect* rect, float xScale, float yScale) {
    rect->fLeft   = SkScalarMul(rect->fLeft,   xScale);
    rect->fTop    = SkScalarMul(rect->fTop,    yScale);
    rect->fRight  = SkScalarMul(rect->fRight,  xScale);
    rect->fBottom = SkScalarMul(rect->fBottom, yScale);
}
Exemplo n.º 3
0
static void eval_sheet(const SkPoint edge[], int nu, int nv, int iu, int iv,
                       SkPoint* pt) {
    const int TL = 0;
    const int TR = nu;
    const int BR = TR + nv;
    const int BL = BR + nu;

    SkScalar u = SkIntToScalar(iu) / nu;
    SkScalar v = SkIntToScalar(iv) / nv;

    SkScalar uv = SkScalarMul(u, v);
    SkScalar Uv = SkScalarMul(SK_Scalar1 - u, v);
    SkScalar uV = SkScalarMul(u, SK_Scalar1 - v);
    SkScalar UV = SkScalarMul(SK_Scalar1 - u, SK_Scalar1 - v);

    SkScalar x0 = SkScalarMul(UV, edge[TL].fX) + SkScalarMul(uV, edge[TR].fX) +
                  SkScalarMul(Uv, edge[BL].fX) + SkScalarMul(uv, edge[BR].fX);
    SkScalar y0 = SkScalarMul(UV, edge[TL].fY) + SkScalarMul(uV, edge[TR].fY) +
                  SkScalarMul(Uv, edge[BL].fY) + SkScalarMul(uv, edge[BR].fY);

    SkScalar x =    SkScalarMul(SK_Scalar1 - v, edge[TL+iu].fX) +
                    SkScalarMul(u, edge[TR+iv].fX) +
                    SkScalarMul(v, edge[BR+nu-iu].fX) +
                    SkScalarMul(SK_Scalar1 - u, edge[BL+nv-iv].fX) - x0;
    SkScalar y =    SkScalarMul(SK_Scalar1 - v, edge[TL+iu].fY) +
                    SkScalarMul(u, edge[TR+iv].fY) +
                    SkScalarMul(v, edge[BR+nu-iu].fY) +
                    SkScalarMul(SK_Scalar1 - u, edge[BL+nv-iv].fY) - y0;
    pt->set(x, y);
}
Exemplo n.º 4
0
struct DegenerateTestData {
    DegenerateTestData() { fStage = kInitial; }
    bool isDegenerate() const { return kNonDegenerate != fStage; }
    enum {
        kInitial,
        kPoint,
        kLine,
        kNonDegenerate
    }           fStage;
    SkPoint     fFirstPoint;
    SkVector    fLineNormal;
    SkScalar    fLineC;
};

static const SkScalar kClose = (SK_Scalar1 / 16);
static const SkScalar kCloseSqd = SkScalarMul(kClose, kClose);

static void update_degenerate_test(DegenerateTestData* data, const SkPoint& pt) {
    switch (data->fStage) {
        case DegenerateTestData::kInitial:
            data->fFirstPoint = pt;
            data->fStage = DegenerateTestData::kPoint;
            break;
        case DegenerateTestData::kPoint:
            if (pt.distanceToSqd(data->fFirstPoint) > kCloseSqd) {
                data->fLineNormal = pt - data->fFirstPoint;
                data->fLineNormal.normalize();
                data->fLineNormal.setOrthog(data->fLineNormal);
                data->fLineC = -data->fLineNormal.dot(data->fFirstPoint);
                data->fStage = DegenerateTestData::kLine;
            }
Exemplo n.º 5
0
// Currently asPoints is more restrictive then it needs to be. In the future
// we need to:
//      allow kRound_Cap capping (could allow rotations in the matrix with this)
//      allow paths to be returned
bool SkDashPathEffect::asPoints(PointData* results,
                                const SkPath& src,
                                const SkStrokeRec& rec,
                                const SkMatrix& matrix,
                                const SkRect* cullRect) const {
    // width < 0 -> fill && width == 0 -> hairline so requiring width > 0 rules both out
    if (fInitialDashLength < 0 || 0 >= rec.getWidth()) {
        return false;
    }

    // TODO: this next test could be eased up. We could allow any number of
    // intervals as long as all the ons match and all the offs match.
    // Additionally, they do not necessarily need to be integers.
    // We cannot allow arbitrary intervals since we want the returned points
    // to be uniformly sized.
    if (fCount != 2 ||
        !SkScalarNearlyEqual(fIntervals[0], fIntervals[1]) ||
        !SkScalarIsInt(fIntervals[0]) ||
        !SkScalarIsInt(fIntervals[1])) {
        return false;
    }

    SkPoint pts[2];

    if (!src.isLine(pts)) {
        return false;
    }

    // TODO: this test could be eased up to allow circles
    if (SkPaint::kButt_Cap != rec.getCap()) {
        return false;
    }

    // TODO: this test could be eased up for circles. Rotations could be allowed.
    if (!matrix.rectStaysRect()) {
        return false;
    }

    SkScalar        length = SkPoint::Distance(pts[1], pts[0]);

    SkVector tangent = pts[1] - pts[0];
    if (tangent.isZero()) {
        return false;
    }

    tangent.scale(SkScalarInvert(length));

    // TODO: make this test for horizontal & vertical lines more robust
    bool isXAxis = true;
    if (SK_Scalar1 == tangent.fX || -SK_Scalar1 == tangent.fX) {
        results->fSize.set(SkScalarHalf(fIntervals[0]), SkScalarHalf(rec.getWidth()));
    } else if (SK_Scalar1 == tangent.fY || -SK_Scalar1 == tangent.fY) {
        results->fSize.set(SkScalarHalf(rec.getWidth()), SkScalarHalf(fIntervals[0]));
        isXAxis = false;
    } else if (SkPaint::kRound_Cap != rec.getCap()) {
        // Angled lines don't have axis-aligned boxes.
        return false;
    }

    if (NULL != results) {
        results->fFlags = 0;
        SkScalar clampedInitialDashLength = SkMinScalar(length, fInitialDashLength);

        if (SkPaint::kRound_Cap == rec.getCap()) {
            results->fFlags |= PointData::kCircles_PointFlag;
        }

        results->fNumPoints = 0;
        SkScalar len2 = length;
        if (clampedInitialDashLength > 0 || 0 == fInitialDashIndex) {
            SkASSERT(len2 >= clampedInitialDashLength);
            if (0 == fInitialDashIndex) {
                if (clampedInitialDashLength > 0) {
                    if (clampedInitialDashLength >= fIntervals[0]) {
                        ++results->fNumPoints;  // partial first dash
                    }
                    len2 -= clampedInitialDashLength;
                }
                len2 -= fIntervals[1];  // also skip first space
                if (len2 < 0) {
                    len2 = 0;
                }
            } else {
                len2 -= clampedInitialDashLength; // skip initial partial empty
            }
        }
        int numMidPoints = SkScalarFloorToInt(SkScalarDiv(len2, fIntervalLength));
        results->fNumPoints += numMidPoints;
        len2 -= numMidPoints * fIntervalLength;
        bool partialLast = false;
        if (len2 > 0) {
            if (len2 < fIntervals[0]) {
                partialLast = true;
            } else {
                ++numMidPoints;
                ++results->fNumPoints;
            }
        }

        results->fPoints = new SkPoint[results->fNumPoints];

        SkScalar    distance = 0;
        int         curPt = 0;

        if (clampedInitialDashLength > 0 || 0 == fInitialDashIndex) {
            SkASSERT(clampedInitialDashLength <= length);

            if (0 == fInitialDashIndex) {
                if (clampedInitialDashLength > 0) {
                    // partial first block
                    SkASSERT(SkPaint::kRound_Cap != rec.getCap()); // can't handle partial circles
                    SkScalar x = pts[0].fX + SkScalarMul(tangent.fX, SkScalarHalf(clampedInitialDashLength));
                    SkScalar y = pts[0].fY + SkScalarMul(tangent.fY, SkScalarHalf(clampedInitialDashLength));
                    SkScalar halfWidth, halfHeight;
                    if (isXAxis) {
                        halfWidth = SkScalarHalf(clampedInitialDashLength);
                        halfHeight = SkScalarHalf(rec.getWidth());
                    } else {
                        halfWidth = SkScalarHalf(rec.getWidth());
                        halfHeight = SkScalarHalf(clampedInitialDashLength);
                    }
                    if (clampedInitialDashLength < fIntervals[0]) {
                        // This one will not be like the others
                        results->fFirst.addRect(x - halfWidth, y - halfHeight,
                                                x + halfWidth, y + halfHeight);
                    } else {
                        SkASSERT(curPt < results->fNumPoints);
                        results->fPoints[curPt].set(x, y);
                        ++curPt;
                    }

                    distance += clampedInitialDashLength;
                }

                distance += fIntervals[1];  // skip over the next blank block too
            } else {
                distance += clampedInitialDashLength;
            }
        }

        if (0 != numMidPoints) {
            distance += SkScalarHalf(fIntervals[0]);

            for (int i = 0; i < numMidPoints; ++i) {
                SkScalar x = pts[0].fX + SkScalarMul(tangent.fX, distance);
                SkScalar y = pts[0].fY + SkScalarMul(tangent.fY, distance);

                SkASSERT(curPt < results->fNumPoints);
                results->fPoints[curPt].set(x, y);
                ++curPt;

                distance += fIntervalLength;
            }

            distance -= SkScalarHalf(fIntervals[0]);
        }

        if (partialLast) {
            // partial final block
            SkASSERT(SkPaint::kRound_Cap != rec.getCap()); // can't handle partial circles
            SkScalar temp = length - distance;
            SkASSERT(temp < fIntervals[0]);
            SkScalar x = pts[0].fX + SkScalarMul(tangent.fX, distance + SkScalarHalf(temp));
            SkScalar y = pts[0].fY + SkScalarMul(tangent.fY, distance + SkScalarHalf(temp));
            SkScalar halfWidth, halfHeight;
            if (isXAxis) {
                halfWidth = SkScalarHalf(temp);
                halfHeight = SkScalarHalf(rec.getWidth());
            } else {
                halfWidth = SkScalarHalf(rec.getWidth());
                halfHeight = SkScalarHalf(temp);
            }
            results->fLast.addRect(x - halfWidth, y - halfHeight,
                                   x + halfWidth, y + halfHeight);
        }

        SkASSERT(curPt == results->fNumPoints);
    }

    return true;
}
Exemplo n.º 6
0
bool SkScriptRuntime::executeTokens(unsigned char* opCode) {
    SkOperand2 operand[2];    // 1=accumulator and 2=operand
    SkScriptEngine2::TypeOp op;
    size_t ref;
    int index, size;
    int registerLoad;
    SkScriptCallBack* callBack SK_INIT_TO_AVOID_WARNING;
    do {
    switch ((op = (SkScriptEngine2::TypeOp) *opCode++)) {
        case SkScriptEngine2::kArrayToken:    // create an array
            operand[0].fArray = new SkOpArray(SkOperand2::kNoType /*fReturnType*/);
            break;
        case SkScriptEngine2::kArrayIndex:    // array accessor
            index = operand[1].fS32;
            if (index >= operand[0].fArray->count()) {
                fError = kArrayIndexOutOfBounds;
                return false;
            }
            operand[0] = operand[0].fArray->begin()[index];
            break;
        case SkScriptEngine2::kArrayParam:    // array initializer, or function param
            *operand[0].fArray->append() = operand[1];
            break;
        case SkScriptEngine2::kCallback:
            memcpy(&index, opCode, sizeof(index));
            opCode += sizeof(index);
            callBack = fCallBackArray[index];
            break;
        case SkScriptEngine2::kFunctionCall: {
            memcpy(&ref, opCode, sizeof(ref));
            opCode += sizeof(ref);
            SkScriptCallBackFunction* callBackFunction = (SkScriptCallBackFunction*) callBack;
            if (callBackFunction->invoke(ref, operand[0].fArray, /* params */
                    &operand[0] /* result */) == false) {
                fError = kFunctionCallFailed;
                return false;
            }
            } break;
        case SkScriptEngine2::kMemberOp: {
            memcpy(&ref, opCode, sizeof(ref));
            opCode += sizeof(ref);
            SkScriptCallBackMember* callBackMember = (SkScriptCallBackMember*) callBack;
            if (callBackMember->invoke(ref, operand[0].fObject, &operand[0]) == false) {
                fError = kMemberOpFailed;
                return false;
            }
            } break;
        case SkScriptEngine2::kPropertyOp: {
            memcpy(&ref, opCode, sizeof(ref));
            opCode += sizeof(ref);
            SkScriptCallBackProperty* callBackProperty = (SkScriptCallBackProperty*) callBack;
            if (callBackProperty->getResult(ref, &operand[0])== false) {
                fError = kPropertyOpFailed;
                return false;
            }
            } break;
        case SkScriptEngine2::kAccumulatorPop:
            fRunStack.pop(&operand[0]);
            break;
        case SkScriptEngine2::kAccumulatorPush:
            *fRunStack.push() = operand[0];
            break;
        case SkScriptEngine2::kIntegerAccumulator:
        case SkScriptEngine2::kIntegerOperand:
            registerLoad = op - SkScriptEngine2::kIntegerAccumulator;
            memcpy(&operand[registerLoad].fS32, opCode, sizeof(int32_t));
            opCode += sizeof(int32_t);
            break;
        case SkScriptEngine2::kScalarAccumulator:
        case SkScriptEngine2::kScalarOperand:
            registerLoad = op - SkScriptEngine2::kScalarAccumulator;
            memcpy(&operand[registerLoad].fScalar, opCode, sizeof(SkScalar));
            opCode += sizeof(SkScalar);
            break;
        case SkScriptEngine2::kStringAccumulator:
        case SkScriptEngine2::kStringOperand: {
            SkString* strPtr = new SkString();
            track(strPtr);
            registerLoad = op - SkScriptEngine2::kStringAccumulator;
            memcpy(&size, opCode, sizeof(size));
            opCode += sizeof(size);
            strPtr->set((char*) opCode, size);
            opCode += size;
            operand[registerLoad].fString = strPtr;
            } break;
        case SkScriptEngine2::kStringTrack: // call after kObjectToValue
            track(operand[0].fString);
            break;
        case SkScriptEngine2::kBoxToken: {
            SkOperand2::OpType type;
            memcpy(&type, opCode, sizeof(type));
            opCode += sizeof(type);
            SkScriptCallBackConvert* callBackBox = (SkScriptCallBackConvert*) callBack;
            if (callBackBox->convert(type, &operand[0]) == false)
                return false;
            } break;
        case SkScriptEngine2::kUnboxToken:
        case SkScriptEngine2::kUnboxToken2: {
            SkScriptCallBackConvert* callBackUnbox = (SkScriptCallBackConvert*) callBack;
            if (callBackUnbox->convert(SkOperand2::kObject, &operand[0]) == false)
                return false;
            } break;
        case SkScriptEngine2::kIfOp:
        case SkScriptEngine2::kLogicalAndInt:
            memcpy(&size, opCode, sizeof(size));
            opCode += sizeof(size);
            if (operand[0].fS32 == 0)
                opCode += size; // skip to else (or end of if predicate)
            break;
        case SkScriptEngine2::kElseOp:
            memcpy(&size, opCode, sizeof(size));
            opCode += sizeof(size);
            opCode += size; // if true: after predicate, always skip to end of else
            break;
        case SkScriptEngine2::kLogicalOrInt:
            memcpy(&size, opCode, sizeof(size));
            opCode += sizeof(size);
            if (operand[0].fS32 != 0)
                opCode += size; // skip to kToBool opcode after || predicate
            break;
        // arithmetic conversion ops
        case SkScriptEngine2::kFlipOpsOp:
            SkTSwap(operand[0], operand[1]);
            break;
        case SkScriptEngine2::kIntToString:
        case SkScriptEngine2::kIntToString2:
        case SkScriptEngine2::kScalarToString:
        case SkScriptEngine2::kScalarToString2:{
            SkString* strPtr = new SkString();
            track(strPtr);
            if (op == SkScriptEngine2::kIntToString || op == SkScriptEngine2::kIntToString2)
                strPtr->appendS32(operand[op - SkScriptEngine2::kIntToString].fS32);
            else
                strPtr->appendScalar(operand[op - SkScriptEngine2::kScalarToString].fScalar);
            operand[0].fString = strPtr;
            } break;
        case SkScriptEngine2::kIntToScalar:
        case SkScriptEngine2::kIntToScalar2:
            operand[0].fScalar = SkScriptEngine2::IntToScalar(operand[op - SkScriptEngine2::kIntToScalar].fS32);
            break;
        case SkScriptEngine2::kStringToInt:
            if (SkParse::FindS32(operand[0].fString->c_str(), &operand[0].fS32) == NULL)
                return false;
            break;
        case SkScriptEngine2::kStringToScalar:
        case SkScriptEngine2::kStringToScalar2:
            if (SkParse::FindScalar(operand[0].fString->c_str(),
                    &operand[op - SkScriptEngine2::kStringToScalar].fScalar) == NULL)
                return false;
            break;
        case SkScriptEngine2::kScalarToInt:
            operand[0].fS32 = SkScalarFloorToInt(operand[0].fScalar);
            break;
        // arithmetic ops
        case SkScriptEngine2::kAddInt:
            operand[0].fS32 += operand[1].fS32;
            break;
        case SkScriptEngine2::kAddScalar:
            operand[0].fScalar += operand[1].fScalar;
            break;
        case SkScriptEngine2::kAddString:
//            if (fTrackString.find(operand[1].fString) < 0) {
//                operand[1].fString = SkNEW_ARGS(SkString, (*operand[1].fString));
//                track(operand[1].fString);
//            }
            operand[0].fString->append(*operand[1].fString);
            break;
        case SkScriptEngine2::kBitAndInt:
            operand[0].fS32 &= operand[1].fS32;
            break;
        case SkScriptEngine2::kBitNotInt:
            operand[0].fS32 = ~operand[0].fS32;
            break;
        case SkScriptEngine2::kBitOrInt:
            operand[0].fS32 |= operand[1].fS32;
            break;
        case SkScriptEngine2::kDivideInt:
            SkASSERT(operand[1].fS32 != 0);
            if (operand[1].fS32 == 0)
                operand[0].fS32 = operand[0].fS32 == 0 ? SK_NaN32 :
                    operand[0].fS32 > 0 ? SK_MaxS32 : -SK_MaxS32;
            else
            if (operand[1].fS32 != 0) // throw error on divide by zero?
                operand[0].fS32 /= operand[1].fS32;
            break;
        case SkScriptEngine2::kDivideScalar:
            if (operand[1].fScalar == 0)
                operand[0].fScalar = operand[0].fScalar == 0 ? SK_ScalarNaN :
                    operand[0].fScalar > 0 ? SK_ScalarMax : -SK_ScalarMax;
            else
                operand[0].fScalar = operand[0].fScalar / operand[1].fScalar;
            break;
        case SkScriptEngine2::kEqualInt:
            operand[0].fS32 = operand[0].fS32 == operand[1].fS32;
            break;
        case SkScriptEngine2::kEqualScalar:
            operand[0].fS32 = operand[0].fScalar == operand[1].fScalar;
            break;
        case SkScriptEngine2::kEqualString:
            operand[0].fS32 = *operand[0].fString == *operand[1].fString;
            break;
        case SkScriptEngine2::kGreaterEqualInt:
            operand[0].fS32 = operand[0].fS32 >= operand[1].fS32;
            break;
        case SkScriptEngine2::kGreaterEqualScalar:
            operand[0].fS32 = operand[0].fScalar >= operand[1].fScalar;
            break;
        case SkScriptEngine2::kGreaterEqualString:
            operand[0].fS32 = strcmp(operand[0].fString->c_str(), operand[1].fString->c_str()) >= 0;
            break;
        case SkScriptEngine2::kToBool:
            operand[0].fS32 = !! operand[0].fS32;
            break;
        case SkScriptEngine2::kLogicalNotInt:
            operand[0].fS32 = ! operand[0].fS32;
            break;
        case SkScriptEngine2::kMinusInt:
            operand[0].fS32 = -operand[0].fS32;
            break;
        case SkScriptEngine2::kMinusScalar:
            operand[0].fScalar = -operand[0].fScalar;
            break;
        case SkScriptEngine2::kModuloInt:
            operand[0].fS32 %= operand[1].fS32;
            break;
        case SkScriptEngine2::kModuloScalar:
            operand[0].fScalar = SkScalarMod(operand[0].fScalar, operand[1].fScalar);
            break;
        case SkScriptEngine2::kMultiplyInt:
            operand[0].fS32 *= operand[1].fS32;
            break;
        case SkScriptEngine2::kMultiplyScalar:
            operand[0].fScalar = SkScalarMul(operand[0].fScalar, operand[1].fScalar);
            break;
        case SkScriptEngine2::kShiftLeftInt:
            operand[0].fS32 <<= operand[1].fS32;
            break;
        case SkScriptEngine2::kShiftRightInt:
            operand[0].fS32 >>= operand[1].fS32;
            break;
        case SkScriptEngine2::kSubtractInt:
            operand[0].fS32 -= operand[1].fS32;
            break;
        case SkScriptEngine2::kSubtractScalar:
            operand[0].fScalar -= operand[1].fScalar;
            break;
        case SkScriptEngine2::kXorInt:
            operand[0].fS32 ^= operand[1].fS32;
            break;
        case SkScriptEngine2::kEnd:
            goto done;
        case SkScriptEngine2::kNop:
                SkASSERT(0);
    default:
        break;
    }
    } while (true);
done:
    fRunStack.push(operand[0]);
    return true;
}
void SkScalerContext::Rec::getLocalMatrix(SkMatrix* m) const
{
    m->setScale(SkScalarMul(fTextSize, fPreScaleX), fTextSize);
    if (fPreSkewX)
        m->postSkew(fPreSkewX, 0);
}
Exemplo n.º 8
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();)
}
Exemplo n.º 9
0
void SkPoint::scale(SkScalar scale, SkPoint* dst) const {
    SkASSERT(dst);
    dst->set(SkScalarMul(fX, scale), SkScalarMul(fY, scale));
}
Exemplo n.º 10
0
void GrAARectRenderer::StrokeAARect(GrDrawTarget* target,
                                    GrPipelineBuilder* pipelineBuilder,
                                    GrColor color,
                                    const SkMatrix& viewMatrix,
                                    const SkRect& rect,
                                    const SkRect& devRect,
                                    const SkStrokeRec& stroke) {
    SkVector devStrokeSize;
    SkScalar width = stroke.getWidth();
    if (width > 0) {
        devStrokeSize.set(width, width);
        viewMatrix.mapVectors(&devStrokeSize, 1);
        devStrokeSize.setAbs(devStrokeSize);
    } else {
        devStrokeSize.set(SK_Scalar1, SK_Scalar1);
    }

    const SkScalar dx = devStrokeSize.fX;
    const SkScalar dy = devStrokeSize.fY;
    const SkScalar rx = SkScalarMul(dx, SK_ScalarHalf);
    const SkScalar ry = SkScalarMul(dy, SK_ScalarHalf);

    SkScalar spare;
    {
        SkScalar w = devRect.width() - dx;
        SkScalar h = devRect.height() - dy;
        spare = SkTMin(w, h);
    }

    SkRect devOutside(devRect);
    devOutside.outset(rx, ry);

    bool miterStroke = true;
    // For hairlines, make bevel and round joins appear the same as mitered ones.
    // small miter limit means right angles show bevel...
    if ((width > 0) && (stroke.getJoin() != SkPaint::kMiter_Join ||
                        stroke.getMiter() < SK_ScalarSqrt2)) {
        miterStroke = false;
    }

    if (spare <= 0 && miterStroke) {
        FillAARect(target, pipelineBuilder, color, viewMatrix, devOutside, devOutside);
        return;
    }

    SkRect devInside(devRect);
    devInside.inset(rx, ry);

    SkRect devOutsideAssist(devRect);

    // For bevel-stroke, use 2 SkRect instances(devOutside and devOutsideAssist)
    // to draw the outer of the rect. Because there are 8 vertices on the outer
    // edge, while vertex number of inner edge is 4, the same as miter-stroke.
    if (!miterStroke) {
        devOutside.inset(0, ry);
        devOutsideAssist.outset(0, ry);
    }

    GeometryStrokeAARect(target, pipelineBuilder, color, viewMatrix, devOutside,
                         devOutsideAssist, devInside, miterStroke);
}
Exemplo n.º 11
0
void SkTextBox::draw(SkCanvas* canvas, const char text[], size_t len, const SkPaint& paint)
{
    SkASSERT(canvas && &paint && (text || len == 0));

    SkScalar marginWidth = fBox.width();

    if (marginWidth <= 0 || len == 0)
        return;

    const char* textStop = text + len;

    SkScalar                x, y, scaledSpacing, height, fontHeight;
    SkPaint::FontMetrics    metrics;

    switch (paint.getTextAlign()) {
    case SkPaint::kLeft_Align:
        x = 0;
        break;
    case SkPaint::kCenter_Align:
        x = SkScalarHalf(marginWidth);
        break;
    default:
        x = marginWidth;
        break;
    }
    x += fBox.fLeft;

    fontHeight = paint.getFontMetrics(&metrics);
    scaledSpacing = SkScalarMul(fontHeight, fSpacingMul) + fSpacingAdd;
    height = fBox.height();

    //  compute Y position for first line
    {
        SkScalar textHeight = fontHeight;

        if (fMode == kLineBreak_Mode && fSpacingAlign != kStart_SpacingAlign)
        {
            int count = SkTextLineBreaker::CountLines(text, textStop - text, paint, marginWidth);
            SkASSERT(count > 0);
            textHeight += scaledSpacing * (count - 1);
        }

        switch (fSpacingAlign) {
        case kStart_SpacingAlign:
            y = 0;
            break;
        case kCenter_SpacingAlign:
            y = SkScalarHalf(height - textHeight);
            break;
        default:
            SkASSERT(fSpacingAlign == kEnd_SpacingAlign);
            y = height - textHeight;
            break;
        }
        y += fBox.fTop - metrics.fAscent;
    }

    for (;;)
    {
        len = linebreak(text, textStop, paint, marginWidth);
        if (y + metrics.fDescent + metrics.fLeading > 0)
            canvas->drawText(text, len, x, y, paint);
        text += len;
        if (text >= textStop)
            break;
        y += scaledSpacing;
        if (y + metrics.fAscent >= height)
            break;
    } 
}
Exemplo n.º 12
0
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 = SkScalarCeilToScalar(input);
            break;
        case SK_FUNCTION(cos):
            scalarResult = SkScalarCos(input);
            break;
        case SK_FUNCTION(exp):
            scalarResult = SkScalarExp(input);
            break;
        case SK_FUNCTION(floor):
            scalarResult = SkScalarFloorToScalar(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 = SkScalarRoundToScalar(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;
}
Exemplo n.º 13
0
void GrAARectRenderer::strokeAARect(GrGpu* gpu,
                                    GrDrawTarget* target,
                                    const GrRect& devRect,
                                    const GrVec& devStrokeSize,
                                    bool useVertexCoverage) {
    const SkScalar& dx = devStrokeSize.fX;
    const SkScalar& dy = devStrokeSize.fY;
    const SkScalar rx = SkScalarMul(dx, SK_ScalarHalf);
    const SkScalar ry = SkScalarMul(dy, SK_ScalarHalf);

    SkScalar spare;
    {
        SkScalar w = devRect.width() - dx;
        SkScalar h = devRect.height() - dy;
        spare = GrMin(w, h);
    }

    if (spare <= 0) {
        GrRect r(devRect);
        r.inset(-rx, -ry);
        this->fillAARect(gpu, target, r, useVertexCoverage);
        return;
    }
    GrVertexLayout layout = aa_rect_layout(useVertexCoverage);
    size_t vsize = GrDrawState::VertexSize(layout);

    GrDrawTarget::AutoReleaseGeometry geo(target, layout, 16, 0);
    if (!geo.succeeded()) {
        GrPrintf("Failed to get space for vertices!\n");
        return;
    }
    GrIndexBuffer* indexBuffer = this->aaStrokeRectIndexBuffer(gpu);
    if (NULL == indexBuffer) {
        GrPrintf("Failed to create index buffer!\n");
        return;
    }

    intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());

    // We create vertices for four nested rectangles. There are two ramps from 0 to full
    // coverage, one on the exterior of the stroke and the other on the interior.
    // The following pointers refer to the four rects, from outermost to innermost.
    GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
    GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
    GrPoint* fan2Pos = reinterpret_cast<GrPoint*>(verts + 8 * vsize);
    GrPoint* fan3Pos = reinterpret_cast<GrPoint*>(verts + 12 * vsize);

    set_inset_fan(fan0Pos, vsize, devRect,
                  -rx - SK_ScalarHalf, -ry - SK_ScalarHalf);
    set_inset_fan(fan1Pos, vsize, devRect,
                  -rx + SK_ScalarHalf, -ry + SK_ScalarHalf);
    set_inset_fan(fan2Pos, vsize, devRect,
                  rx - SK_ScalarHalf,  ry - SK_ScalarHalf);
    set_inset_fan(fan3Pos, vsize, devRect,
                  rx + SK_ScalarHalf,  ry + SK_ScalarHalf);

    // The outermost rect has 0 coverage
    verts += sizeof(GrPoint);
    for (int i = 0; i < 4; ++i) {
        *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
    }

    // The inner two rects have full coverage
    GrColor innerColor;
    if (useVertexCoverage) {
        innerColor = 0xffffffff;
    } else {
        innerColor = target->getDrawState().getColor();
    }
    verts += 4 * vsize;
    for (int i = 0; i < 8; ++i) {
        *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
    }

    // The innermost rect has full coverage
    verts += 8 * vsize;
    for (int i = 0; i < 4; ++i) {
        *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
    }

    target->setIndexSourceToBuffer(indexBuffer);
    target->drawIndexed(kTriangles_GrPrimitiveType,
                        0, 0, 16, aaStrokeRectIndexCount());
}
Exemplo n.º 14
0
void GrStencilAndCoverTextContext::init(const GrPaint& paint,
                                        const SkPaint& skPaint,
                                        size_t textByteLength,
                                        RenderMode renderMode,
                                        SkScalar textTranslateY) {
    GrTextContext::init(paint, skPaint);

    fContextInitialMatrix = fContext->getMatrix();

    const bool otherBackendsWillDrawAsPaths =
        SkDraw::ShouldDrawTextAsPaths(skPaint, fContextInitialMatrix);

    fNeedsDeviceSpaceGlyphs = !otherBackendsWillDrawAsPaths &&
                              kMaxAccuracy_RenderMode == renderMode &&
                              SkToBool(fContextInitialMatrix.getType() &
                                       (SkMatrix::kScale_Mask | SkMatrix::kAffine_Mask));

    if (fNeedsDeviceSpaceGlyphs) {
        // SkDraw::ShouldDrawTextAsPaths takes care of perspective transforms.
        SkASSERT(!fContextInitialMatrix.hasPerspective());
        SkASSERT(0 == textTranslateY); // TODO: Handle textTranslateY in device-space usecase.

        fTextRatio = fTextInverseRatio = 1.0f;

        // Glyphs loaded by GPU path rendering have an inverted y-direction.
        SkMatrix m;
        m.setScale(1, -1);
        fContext->setMatrix(m);

        // Post-flip the initial matrix so we're left with just the flip after
        // the paint preConcats the inverse.
        m = fContextInitialMatrix;
        m.postScale(1, -1);
        fPaint.localCoordChangeInverse(m);

        // The whole shape (including stroke) will be baked into the glyph outlines. Make
        // NVPR just fill the baked shapes.
        fGlyphCache = fSkPaint.detachCache(&fDeviceProperties, &fContextInitialMatrix, false);
        fGlyphs = get_gr_glyphs(fContext, fGlyphCache->getScalerContext()->getTypeface(),
                                &fGlyphCache->getDescriptor(),
                                SkStrokeRec(SkStrokeRec::kFill_InitStyle));
    } else {
        // Don't bake strokes into the glyph outlines. We will stroke the glyphs
        // using the GPU instead. This is the fast path.
        SkStrokeRec gpuStroke = SkStrokeRec(fSkPaint);
        fSkPaint.setStyle(SkPaint::kFill_Style);

        if (gpuStroke.isHairlineStyle()) {
            // Approximate hairline stroke.
            SkScalar strokeWidth = SK_Scalar1 /
                (SkVector::Make(fContextInitialMatrix.getScaleX(),
                                fContextInitialMatrix.getSkewY()).length());
            gpuStroke.setStrokeStyle(strokeWidth, false /*strokeAndFill*/);

        } else if (fSkPaint.isFakeBoldText() &&
#ifdef SK_USE_FREETYPE_EMBOLDEN
                   kMaxPerformance_RenderMode == renderMode &&
#endif
                   SkStrokeRec::kStroke_Style != gpuStroke.getStyle()) {

            // Instead of baking fake bold into the glyph outlines, do it with the GPU stroke.
            SkScalar fakeBoldScale = SkScalarInterpFunc(fSkPaint.getTextSize(),
                                                        kStdFakeBoldInterpKeys,
                                                        kStdFakeBoldInterpValues,
                                                        kStdFakeBoldInterpLength);
            SkScalar extra = SkScalarMul(fSkPaint.getTextSize(), fakeBoldScale);
            gpuStroke.setStrokeStyle(gpuStroke.needToApply() ? gpuStroke.getWidth() + extra : extra,
                                     true /*strokeAndFill*/);

            fSkPaint.setFakeBoldText(false);
        }

        bool canUseRawPaths;

        if (otherBackendsWillDrawAsPaths || kMaxPerformance_RenderMode == renderMode) {
            // We can draw the glyphs from canonically sized paths.
            fTextRatio = fSkPaint.getTextSize() / SkPaint::kCanonicalTextSizeForPaths;
            fTextInverseRatio = SkPaint::kCanonicalTextSizeForPaths / fSkPaint.getTextSize();

            // Compensate for the glyphs being scaled by fTextRatio.
            if (!gpuStroke.isFillStyle()) {
                gpuStroke.setStrokeStyle(gpuStroke.getWidth() / fTextRatio,
                                         SkStrokeRec::kStrokeAndFill_Style == gpuStroke.getStyle());
            }

            fSkPaint.setLinearText(true);
            fSkPaint.setLCDRenderText(false);
            fSkPaint.setAutohinted(false);
            fSkPaint.setHinting(SkPaint::kNo_Hinting);
            fSkPaint.setSubpixelText(true);
            fSkPaint.setTextSize(SkIntToScalar(SkPaint::kCanonicalTextSizeForPaths));

            canUseRawPaths = SK_Scalar1 == fSkPaint.getTextScaleX() &&
                             0 == fSkPaint.getTextSkewX() &&
                             !fSkPaint.isFakeBoldText() &&
                             !fSkPaint.isVerticalText();
        } else {
            fTextRatio = fTextInverseRatio = 1.0f;
            canUseRawPaths = false;
        }

        SkMatrix textMatrix;
        textMatrix.setTranslate(0, textTranslateY);
        // Glyphs loaded by GPU path rendering have an inverted y-direction.
        textMatrix.preScale(fTextRatio, -fTextRatio);
        fPaint.localCoordChange(textMatrix);
        fContext->concatMatrix(textMatrix);

        fGlyphCache = fSkPaint.detachCache(&fDeviceProperties, NULL, false);
        fGlyphs = canUseRawPaths ?
                      get_gr_glyphs(fContext, fSkPaint.getTypeface(), NULL, gpuStroke) :
                      get_gr_glyphs(fContext, fGlyphCache->getScalerContext()->getTypeface(),
                                    &fGlyphCache->getDescriptor(), gpuStroke);
    }

    fStateRestore.set(fDrawTarget->drawState());

    fDrawTarget->drawState()->setFromPaint(fPaint, fContext->getMatrix(),
                                           fContext->getRenderTarget());

    GR_STATIC_CONST_SAME_STENCIL(kStencilPass,
                                 kZero_StencilOp,
                                 kZero_StencilOp,
                                 kNotEqual_StencilFunc,
                                 0xffff,
                                 0x0000,
                                 0xffff);

    *fDrawTarget->drawState()->stencil() = kStencilPass;

    SkASSERT(0 == fPendingGlyphCount);
}