Index: src/core/SkLinearBitmapPipeline.cpp |
diff --git a/src/core/SkLinearBitmapPipeline.cpp b/src/core/SkLinearBitmapPipeline.cpp |
index 4e4226a3206367770dd35682e00e856479b0b7c3..3410ec1727f54c417e7623209a35ed552f4f419e 100644 |
--- a/src/core/SkLinearBitmapPipeline.cpp |
+++ b/src/core/SkLinearBitmapPipeline.cpp |
@@ -65,7 +65,10 @@ public: |
class SkLinearBitmapPipeline::PixelPlacerInterface { |
public: |
virtual ~PixelPlacerInterface() { } |
- virtual void setDestination(SkPM4f* dst) = 0; |
+ // Count is normally not needed, but in these early stages of development it is useful to |
+ // check bounds. |
+ // TODO(herb): 4/6/2016 - remove count when code is stable. |
+ virtual void setDestination(void* dst, int count) = 0; |
virtual void VECTORCALL placePixel(Sk4f pixel0) = 0; |
virtual void VECTORCALL place4Pixels(Sk4f p0, Sk4f p1, Sk4f p2, Sk4f p3) = 0; |
}; |
@@ -238,6 +241,12 @@ public: |
processor->breakIntoEdges(span); |
} |
+ void repeatSpan(Span span, int32_t repeatCount) { |
+ while (repeatCount --> 0) { |
+ processor->pointSpan(span); |
+ } |
+ } |
+ |
BilerpTileStage* processor; |
}; |
@@ -364,13 +373,21 @@ static SkLinearBitmapPipeline::PointProcessorInterface* choose_tiler( |
SkShader::TileMode xMode, |
SkShader::TileMode yMode, |
SkFilterQuality filterQuality, |
- SkLinearBitmapPipeline::TileStage* tileStage) { |
+ SkScalar dx, |
+ SkLinearBitmapPipeline::TileStage* tileStage) |
+{ |
switch (xMode) { |
case SkShader::kClamp_TileMode: |
choose_tiler_ymode<XClampStrategy>(yMode, filterQuality, dimensions, next, tileStage); |
break; |
case SkShader::kRepeat_TileMode: |
- choose_tiler_ymode<XRepeatStrategy>(yMode, filterQuality, dimensions, next, tileStage); |
+ if (dx == 1.0f && filterQuality == kNone_SkFilterQuality) { |
+ choose_tiler_ymode<XRepeatUnitScaleStrategy>( |
+ yMode, kNone_SkFilterQuality, dimensions, next, tileStage); |
+ } else { |
+ choose_tiler_ymode<XRepeatStrategy>( |
+ yMode, filterQuality, dimensions, next, tileStage); |
+ } |
break; |
case SkShader::kMirror_TileMode: |
choose_tiler_ymode<XMirrorStrategy>(yMode, filterQuality, dimensions, next, tileStage); |
@@ -402,7 +419,7 @@ public: |
fSampler.nearestSpan(span); |
} |
- virtual void repeatSpan(Span span, int32_t repeatCount) override { |
+ void repeatSpan(Span span, int32_t repeatCount) override { |
while (repeatCount > 0) { |
fSampler.nearestSpan(span); |
repeatCount--; |
@@ -413,7 +430,7 @@ public: |
SkFAIL("Using nearest neighbor sampler, but calling a bilerpEdge."); |
} |
- virtual void bilerpSpan(Span span, SkScalar y) override { |
+ void bilerpSpan(Span span, SkScalar y) override { |
SkFAIL("Using nearest neighbor sampler, but calling a bilerpSpan."); |
} |
@@ -440,7 +457,7 @@ public: |
fSampler.bilerpSpan(span); |
} |
- virtual void repeatSpan(Span span, int32_t repeatCount) override { |
+ void repeatSpan(Span span, int32_t repeatCount) override { |
while (repeatCount > 0) { |
fSampler.bilerpSpan(span); |
repeatCount--; |
@@ -451,7 +468,7 @@ public: |
fSampler.bilerpEdge(xs, ys); |
} |
- virtual void bilerpSpan(Span span, SkScalar y) override { |
+ void bilerpSpan(Span span, SkScalar y) override { |
fSampler.bilerpSpanWithY(span, y); |
} |
@@ -515,11 +532,13 @@ class PlaceFPPixel final : public SkLinearBitmapPipeline::PixelPlacerInterface { |
public: |
PlaceFPPixel(float postAlpha) : fPostAlpha{postAlpha} { } |
void VECTORCALL placePixel(Sk4f pixel) override { |
+ SkASSERT(fDst + 1 <= fEnd ); |
PlacePixel(fDst, pixel, 0); |
fDst += 1; |
} |
void VECTORCALL place4Pixels(Sk4f p0, Sk4f p1, Sk4f p2, Sk4f p3) override { |
+ SkASSERT(fDst + 4 <= fEnd); |
SkPM4f* dst = fDst; |
PlacePixel(dst, p0, 0); |
PlacePixel(dst, p1, 1); |
@@ -528,8 +547,9 @@ public: |
fDst += 4; |
} |
- void setDestination(SkPM4f* dst) override { |
- fDst = dst; |
+ void setDestination(void* dst, int count) override { |
+ fDst = static_cast<SkPM4f*>(dst); |
+ fEnd = fDst + count; |
} |
private: |
@@ -547,6 +567,7 @@ private: |
} |
SkPM4f* fDst; |
+ SkPM4f* fEnd; |
Sk4f fPostAlpha; |
}; |
@@ -572,7 +593,8 @@ SkLinearBitmapPipeline::SkLinearBitmapPipeline( |
SkFilterQuality filterQuality, |
SkShader::TileMode xTile, SkShader::TileMode yTile, |
float postAlpha, |
- const SkPixmap& srcPixmap) { |
+ const SkPixmap& srcPixmap) |
+{ |
SkISize dimensions = srcPixmap.info().dimensions(); |
const SkImageInfo& srcImageInfo = srcPixmap.info(); |
@@ -588,6 +610,8 @@ SkLinearBitmapPipeline::SkLinearBitmapPipeline( |
} |
} |
+ SkScalar dx = adjustedInverse.getScaleX(); |
+ |
// If it is an index 8 color type, the sampler converts to unpremul for better fidelity. |
SkAlphaType alphaType = srcImageInfo.alphaType(); |
if (srcPixmap.colorType() == kIndex_8_SkColorType) { |
@@ -600,13 +624,13 @@ SkLinearBitmapPipeline::SkLinearBitmapPipeline( |
auto samplerStage = choose_pixel_sampler(placementStage, |
filterQuality, srcPixmap, &fSampleStage); |
auto tilerStage = choose_tiler(samplerStage, |
- dimensions, xTile, yTile, filterQuality, &fTiler); |
+ dimensions, xTile, yTile, filterQuality, dx, &fTiler); |
fFirstStage = choose_matrix(tilerStage, adjustedInverse, &fMatrixStage); |
} |
void SkLinearBitmapPipeline::shadeSpan4f(int x, int y, SkPM4f* dst, int count) { |
SkASSERT(count > 0); |
- fPixelStage->setDestination(dst); |
+ fPixelStage->setDestination(dst, count); |
// The count and length arguments start out in a precise relation in order to keep the |
// math correct through the different stages. Count is the number of pixel to produce. |
// Since the code samples at pixel centers, length is the distance from the center of the |