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; }
// 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 } }
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; }
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 } }
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; }
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 }
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; }