Exemple #1
0
SkPath1DPathEffect::SkPath1DPathEffect(const SkPath& path, SkScalar advance,
    SkScalar phase, Style style) : fPath(path)
{
    SkASSERT(advance > 0 && !path.isEmpty());
    // cleanup their phase parameter, inverting it so that it becomes an
    // offset along the path (to match the interpretation in PostScript)
    if (phase < 0) {
        phase = -phase;
        if (phase > advance) {
            phase = SkScalarMod(phase, advance);
        }
    } else {
        if (phase > advance) {
            phase = SkScalarMod(phase, advance);
        }
        phase = advance - phase;
    }
    // now catch the edge case where phase == advance (within epsilon)
    if (phase >= advance) {
        phase = 0;
    }
    SkASSERT(phase >= 0);

    fAdvance = advance;
    fInitialOffset = phase;

    if ((unsigned)style > kMorph_Style) {
        SkDEBUGF(("SkPath1DPathEffect style enum out of range %d\n", style));
    }
    fStyle = style;
}
Exemple #2
0
// Only handles lines for now. If returns true, dstPath is the new (smaller)
// path. If returns false, then dstPath parameter is ignored.
static bool cull_path(const SkPath& srcPath, const SkStrokeRec& rec,
                      const SkRect* cullRect, SkScalar intervalLength,
                      SkPath* dstPath) {
    if (nullptr == cullRect) {
        return false;
    }

    SkPoint pts[2];
    if (!srcPath.isLine(pts)) {
        return false;
    }

    SkRect bounds = *cullRect;
    outset_for_stroke(&bounds, rec);

    SkScalar dx = pts[1].x() - pts[0].x();
    SkScalar dy = pts[1].y() - pts[0].y();

    // just do horizontal lines for now (lazy)
    if (dy) {
        return false;
    }

    SkScalar minX = pts[0].fX;
    SkScalar maxX = pts[1].fX;

    if (dx < 0) {
        SkTSwap(minX, maxX);
    }

    SkASSERT(minX <= maxX);
    if (maxX < bounds.fLeft || minX > bounds.fRight) {
        return false;
    }

    // Now we actually perform the chop, removing the excess to the left and
    // right of the bounds (keeping our new line "in phase" with the dash,
    // hence the (mod intervalLength).

    if (minX < bounds.fLeft) {
        minX = bounds.fLeft - SkScalarMod(bounds.fLeft - minX,
                                          intervalLength);
    }
    if (maxX > bounds.fRight) {
        maxX = bounds.fRight + SkScalarMod(maxX - bounds.fRight,
                                           intervalLength);
    }

    SkASSERT(maxX >= minX);
    if (dx < 0) {
        SkTSwap(minX, maxX);
    }
    pts[0].fX = minX;
    pts[1].fX = maxX;

    dstPath->moveTo(pts[0]);
    dstPath->lineTo(pts[1]);
    return true;
}
SkDashPathEffect::SkDashPathEffect(const SkScalar intervals[], int count,
                                   SkScalar phase, bool scaleToFit)
        : fScaleToFit(scaleToFit) {
    SkASSERT(intervals);
    SkASSERT(count > 1 && SkAlign2(count) == count);

    fIntervals = (SkScalar*)sk_malloc_throw(sizeof(SkScalar) * count);
    fCount = count;

    SkScalar len = 0;
    for (int i = 0; i < count; i++) {
        SkASSERT(intervals[i] >= 0);
        fIntervals[i] = intervals[i];
        len += intervals[i];
    }
    fIntervalLength = len;

    // watch out for values that might make us go out of bounds
    if ((len > 0) && SkScalarIsFinite(phase) && SkScalarIsFinite(len)) {

        // Adjust phase to be between 0 and len, "flipping" phase if negative.
        // e.g., if len is 100, then phase of -20 (or -120) is equivalent to 80
        if (phase < 0) {
            phase = -phase;
            if (phase > len) {
                phase = SkScalarMod(phase, len);
            }
            phase = len - phase;

            // Due to finite precision, it's possible that phase == len,
            // even after the subtract (if len >>> phase), so fix that here.
            // This fixes http://crbug.com/124652 .
            SkASSERT(phase <= len);
            if (phase == len) {
                phase = 0;
            }
        } else if (phase >= len) {
            phase = SkScalarMod(phase, len);
        }
        SkASSERT(phase >= 0 && phase < len);

        fInitialDashLength = FindFirstInterval(intervals, phase,
                                               &fInitialDashIndex, count);

        SkASSERT(fInitialDashLength >= 0);
        SkASSERT(fInitialDashIndex >= 0 && fInitialDashIndex < fCount);
    } else {
        fInitialDashLength = -1;    // signal bad dash intervals
    }
}
Exemple #4
0
SkScalar SampleCode::GetAnimScalar(SkScalar speed, SkScalar period) {
    SkScalar seconds = SkFloatToScalar(gAnimTime / 1000.0f);
    SkScalar value = SkScalarMul(speed, seconds);
    if (period) {
        value = SkScalarMod(value, period);
    }
    return value;
}
Exemple #5
0
void SkDashPath::CalcDashParameters(SkScalar phase, const SkScalar intervals[], int32_t count,
                                    SkScalar* initialDashLength, int32_t* initialDashIndex,
                                    SkScalar* intervalLength, SkScalar* adjustedPhase) {
    SkScalar len = 0;
    for (int i = 0; i < count; i++) {
        len += intervals[i];
    }
    *intervalLength = len;

    // watch out for values that might make us go out of bounds
    if ((len > 0) && SkScalarIsFinite(phase) && SkScalarIsFinite(len)) {

        // Adjust phase to be between 0 and len, "flipping" phase if negative.
        // e.g., if len is 100, then phase of -20 (or -120) is equivalent to 80
        if (adjustedPhase) {
            if (phase < 0) {
                phase = -phase;
                if (phase > len) {
                    phase = SkScalarMod(phase, len);
                }
                phase = len - phase;

                // Due to finite precision, it's possible that phase == len,
                // even after the subtract (if len >>> phase), so fix that here.
                // This fixes http://crbug.com/124652 .
                SkASSERT(phase <= len);
                if (phase == len) {
                    phase = 0;
                }
            } else if (phase >= len) {
                phase = SkScalarMod(phase, len);
            }
            *adjustedPhase = phase;
        }
        SkASSERT(phase >= 0 && phase < len);

        *initialDashLength = find_first_interval(intervals, phase,
                                                initialDashIndex, count);

        SkASSERT(*initialDashLength >= 0);
        SkASSERT(*initialDashIndex >= 0 && *initialDashIndex < count);
    } else {
        *initialDashLength = -1;    // signal bad dash intervals
    }
}
Exemple #6
0
void SkDashPathEffect::setInternalMembers(SkScalar phase) {
    SkScalar len = 0;
    for (int i = 0; i < fCount; i++) {
        len += fIntervals[i];
    }
    fIntervalLength = len;

    // watch out for values that might make us go out of bounds
    if ((len > 0) && SkScalarIsFinite(phase) && SkScalarIsFinite(len)) {

        // Adjust phase to be between 0 and len, "flipping" phase if negative.
        // e.g., if len is 100, then phase of -20 (or -120) is equivalent to 80
        if (phase < 0) {
            phase = -phase;
            if (phase > len) {
                phase = SkScalarMod(phase, len);
            }
            phase = len - phase;

            // Due to finite precision, it's possible that phase == len,
            // even after the subtract (if len >>> phase), so fix that here.
            // This fixes http://crbug.com/124652 .
            SkASSERT(phase <= len);
            if (phase == len) {
                phase = 0;
            }
        } else if (phase >= len) {
            phase = SkScalarMod(phase, len);
        }
        SkASSERT(phase >= 0 && phase < len);

        fPhase = phase;

        fInitialDashLength = FindFirstInterval(fIntervals, fPhase,
                                               &fInitialDashIndex, fCount);

        SkASSERT(fInitialDashLength >= 0);
        SkASSERT(fInitialDashIndex >= 0 && fInitialDashIndex < fCount);
    } else {
        fInitialDashLength = -1;    // signal bad dash intervals
    }
}
 SkScalar fixUp() {
     if (fMod) {
         fValue = SkScalarMod(fValue, fMod);
     } else {
         if (fValue > fMax) {
             fValue = fMax;
         } else if (fValue < fMin) {
             fValue = fMin;
         }
     }
     return fValue;
 }
Exemple #8
0
SkDashPathEffect::SkDashPathEffect(const SkScalar intervals[], int count, SkScalar phase, bool scaleToFit)
    : fScaleToFit(scaleToFit)
{
    SkASSERT(intervals);
    SkASSERT(count > 1 && SkAlign2(count) == count);

    fIntervals = (SkScalar*)sk_malloc_throw(sizeof(SkScalar) * count);
    fCount = count;

    SkScalar len = 0;
    for (int i = 0; i < count; i++)
    {
        SkASSERT(intervals[i] >= 0);
        fIntervals[i] = intervals[i];
        len += intervals[i];
    }
    fIntervalLength = len;

    if (len > 0)    // we don't handle 0 length dash arrays
    {
        if (phase < 0)
        {
            phase = -phase;
            if (phase > len)
                phase = SkScalarMod(phase, len);
            phase = len - phase;
        }
        else if (phase >= len)
            phase = SkScalarMod(phase, len);

        SkASSERT(phase >= 0 && phase < len);
        fInitialDashLength = FindFirstInterval(intervals, phase, &fInitialDashIndex);

        SkASSERT(fInitialDashLength >= 0);
        SkASSERT(fInitialDashIndex >= 0 && fInitialDashIndex < fCount);
    }
    else
        fInitialDashLength = -1;    // signal bad dash intervals
}
Exemple #9
0
        void advance(const SkRect& bounds) {
            fCenter += fVelocity;
            if (fCenter.fX > bounds.right()) {
                SkASSERT(fVelocity.fX > 0);
                fVelocity.fX = -fVelocity.fX;
            } else if (fCenter.fX < bounds.left()) {
                SkASSERT(fVelocity.fX < 0);
                fVelocity.fX = -fVelocity.fX;
            }
            if (fCenter.fY > bounds.bottom()) {
                if (fVelocity.fY > 0) {
                    fVelocity.fY = -fVelocity.fY;
                }
            } else if (fCenter.fY < bounds.top()) {
                if (fVelocity.fY < 0) {
                    fVelocity.fY = -fVelocity.fY;
                }
            }

            fScale += fDScale;
            if (fScale > 2 || fScale < SK_Scalar1/2) {
                fDScale = -fDScale;
            }

            fRadian += fDRadian;
            fRadian = SkScalarMod(fRadian, 2 * SK_ScalarPI);

            fAlpha += fDAlpha;
            if (fAlpha > 1) {
                fAlpha = 1;
                fDAlpha = -fDAlpha;
            } else if (fAlpha < 0) {
                fAlpha = 0;
                fDAlpha = -fDAlpha;
            }
        }
// Attempt to trim the line to minimally cover the cull rect (currently
// only works for horizontal and vertical lines).
// Return true if processing should continue; false otherwise.
static bool cull_line(SkPoint* pts, const SkStrokeRec& rec,
                      const SkMatrix& ctm, const SkRect* cullRect,
                      const SkScalar intervalLength) {
    if (nullptr == cullRect) {
        SkASSERT(false); // Shouldn't ever occur in practice
        return false;
    }

    SkScalar dx = pts[1].x() - pts[0].x();
    SkScalar dy = pts[1].y() - pts[0].y();

    if ((dx && dy) || (!dx && !dy)) {
        return false;
    }

    SkRect bounds = *cullRect;
    outset_for_stroke(&bounds, rec);

    // cullRect is in device space while pts are in the local coordinate system
    // defined by the ctm. We want our answer in the local coordinate system.

    SkASSERT(ctm.rectStaysRect());
    SkMatrix inv;
    if (!ctm.invert(&inv)) {
        return false;
    }

    inv.mapRect(&bounds);

    if (dx) {
        SkASSERT(dx && !dy);
        SkScalar minX = pts[0].fX;
        SkScalar maxX = pts[1].fX;

        if (dx < 0) {
            SkTSwap(minX, maxX);
        }

        SkASSERT(minX < maxX);
        if (maxX <= bounds.fLeft || minX >= bounds.fRight) {
            return false;
        }

        // Now we actually perform the chop, removing the excess to the left and
        // right of the bounds (keeping our new line "in phase" with the dash,
        // hence the (mod intervalLength).

        if (minX < bounds.fLeft) {
            minX = bounds.fLeft - SkScalarMod(bounds.fLeft - minX, intervalLength);
        }
        if (maxX > bounds.fRight) {
            maxX = bounds.fRight + SkScalarMod(maxX - bounds.fRight, intervalLength);
        }

        SkASSERT(maxX > minX);
        if (dx < 0) {
            SkTSwap(minX, maxX);
        }
        pts[0].fX = minX;
        pts[1].fX = maxX;
    } else {
        SkASSERT(dy && !dx);
        SkScalar minY = pts[0].fY;
        SkScalar maxY = pts[1].fY;

        if (dy < 0) {
            SkTSwap(minY, maxY);
        }

        SkASSERT(minY < maxY);
        if (maxY <= bounds.fTop || minY >= bounds.fBottom) {
            return false;
        }

        // Now we actually perform the chop, removing the excess to the top and
        // bottom of the bounds (keeping our new line "in phase" with the dash,
        // hence the (mod intervalLength).

        if (minY < bounds.fTop) {
            minY = bounds.fTop - SkScalarMod(bounds.fTop - minY, intervalLength);
        }
        if (maxY > bounds.fBottom) {
            maxY = bounds.fBottom + SkScalarMod(maxY - bounds.fBottom, intervalLength);
        }

        SkASSERT(maxY > minY);
        if (dy < 0) {
            SkTSwap(minY, maxY);
        }
        pts[0].fY = minY;
        pts[1].fY = maxY;
    }

    return true;
}
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 = SkScalarDiv(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;
}