зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1916907 - Support linear gradients in DrawTargetWebgl. r=aosmond
This attempts to map linear gradient to 1D textures of sufficient resolution for a given rendered primitive. The 1D texture can then be rendered using the image shader, without having to add any specialized gradient shaders. The 1D ramp textures are much smaller than uploading a texture for an entire fallback primitive, which becomes a significant performance benefit in the case of primitives that take up a large area on screen. In the future it might be possible to cache these ramp textures, but for now they remain uncached. Differential Revision: https://phabricator.services.mozilla.com/D221107
This commit is contained in:
Родитель
d39955ba19
Коммит
7499f0288d
|
@ -2598,24 +2598,91 @@ bool SharedContextWebgl::PruneTextureMemory(size_t aMargin, bool aPruneUnused) {
|
||||||
return mNumTextureHandles < oldItems;
|
return mNumTextureHandles < oldItems;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DrawTargetWebgl::FillRect(const Rect& aRect, const Pattern& aPattern,
|
// Attempt to convert a linear gradient to a 1D ramp texture.
|
||||||
const DrawOptions& aOptions) {
|
Maybe<SurfacePattern> DrawTargetWebgl::LinearGradientToSurface(
|
||||||
if (SupportsPattern(aPattern)) {
|
const RectDouble& aBounds, const Pattern& aPattern) {
|
||||||
RectDouble xformRect = TransformDouble(aRect);
|
MOZ_ASSERT(aPattern.GetType() == PatternType::LINEAR_GRADIENT);
|
||||||
if (aPattern.GetType() == PatternType::COLOR) {
|
const auto& gradient = static_cast<const LinearGradientPattern&>(aPattern);
|
||||||
if (Maybe<Rect> clipped = RectClippedToViewport(xformRect)) {
|
// The gradient points must be transformed by the gradient's matrix.
|
||||||
// If the pattern is transform-invariant and the rect clips to the
|
Point gradBegin = gradient.mMatrix.TransformPoint(gradient.mBegin);
|
||||||
// viewport, just clip drawing to the viewport to avoid transform
|
Point gradEnd = gradient.mMatrix.TransformPoint(gradient.mEnd);
|
||||||
// issues.
|
// Get the gradient points in user-space.
|
||||||
DrawRect(*clipped, aPattern, aOptions, Nothing(), nullptr, false);
|
Point begin = mTransform.TransformPoint(gradBegin);
|
||||||
return;
|
Point end = mTransform.TransformPoint(gradEnd);
|
||||||
|
// Find the normalized direction of the gradient and its length.
|
||||||
|
Point dir = end - begin;
|
||||||
|
float len = dir.Length();
|
||||||
|
dir = dir / len;
|
||||||
|
// Restrict the rendered bounds to fall within the canvas.
|
||||||
|
Rect visBounds = NarrowToFloat(aBounds.SafeIntersect(RectDouble(GetRect())));
|
||||||
|
// Calculate the distances along the gradient direction of the bounds.
|
||||||
|
float dist0 = (visBounds.TopLeft() - begin).DotProduct(dir);
|
||||||
|
float distX = visBounds.width * dir.x;
|
||||||
|
float distY = visBounds.height * dir.y;
|
||||||
|
float minDist = floorf(
|
||||||
|
std::max(dist0 + std::min(distX, 0.0f) + std::min(distY, 0.0f), 0.0f));
|
||||||
|
float maxDist = ceilf(
|
||||||
|
std::min(dist0 + std::max(distX, 0.0f) + std::max(distY, 0.0f), len));
|
||||||
|
// Calculate the approximate size of the ramp texture, and see if it would be
|
||||||
|
// sufficiently smaller than just rendering the primitive.
|
||||||
|
float subLen = maxDist - minDist;
|
||||||
|
if (subLen > 0 && subLen < 0.5f * visBounds.Area()) {
|
||||||
|
// Create a 1D texture to contain the gradient ramp. Reserve two extra
|
||||||
|
// texels at the beginning and end of the ramp to account for clamping.
|
||||||
|
RefPtr<DrawTargetSkia> dt = new DrawTargetSkia;
|
||||||
|
if (dt->Init(IntSize(int32_t(subLen + 2), 1), SurfaceFormat::B8G8R8A8)) {
|
||||||
|
// Fill the section of the gradient ramp that is actually used.
|
||||||
|
dt->FillRect(Rect(dt->GetRect()),
|
||||||
|
LinearGradientPattern(Point(1 - minDist, 0.0f),
|
||||||
|
Point(len + 1 - minDist, 0.0f),
|
||||||
|
gradient.mStops));
|
||||||
|
if (RefPtr<SourceSurface> snapshot = dt->Snapshot()) {
|
||||||
|
// Calculate a matrix that will map the gradient ramp texture onto the
|
||||||
|
// actual direction of the gradient.
|
||||||
|
Point gradDir = (gradEnd - gradBegin) / len;
|
||||||
|
Point tangent = Point(-gradDir.y, gradDir.x) / gradDir.Length();
|
||||||
|
SurfacePattern surfacePattern(
|
||||||
|
snapshot, ExtendMode::CLAMP,
|
||||||
|
Matrix(gradDir.x, gradDir.y, tangent.x, tangent.y, gradBegin.x,
|
||||||
|
gradBegin.y)
|
||||||
|
.PreTranslate(minDist - 1, 0));
|
||||||
|
if (SupportsPattern(surfacePattern)) {
|
||||||
|
return Some(surfacePattern);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (RectInsidePrecisionLimits(xformRect)) {
|
}
|
||||||
DrawRect(aRect, aPattern, aOptions);
|
return Nothing();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DrawTargetWebgl::FillRect(const Rect& aRect, const Pattern& aPattern,
|
||||||
|
const DrawOptions& aOptions) {
|
||||||
|
RectDouble xformRect = TransformDouble(aRect);
|
||||||
|
if (aPattern.GetType() == PatternType::COLOR) {
|
||||||
|
if (Maybe<Rect> clipped = RectClippedToViewport(xformRect)) {
|
||||||
|
// If the pattern is transform-invariant and the rect clips to the
|
||||||
|
// viewport, just clip drawing to the viewport to avoid transform
|
||||||
|
// issues.
|
||||||
|
DrawRect(*clipped, aPattern, aOptions, Nothing(), nullptr, false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (RectInsidePrecisionLimits(xformRect)) {
|
||||||
|
if (SupportsPattern(aPattern)) {
|
||||||
|
DrawRect(aRect, aPattern, aOptions);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (aPattern.GetType() == PatternType::LINEAR_GRADIENT) {
|
||||||
|
if (Maybe<SurfacePattern> surface =
|
||||||
|
LinearGradientToSurface(xformRect, aPattern)) {
|
||||||
|
if (DrawRect(aRect, *surface, aOptions, Nothing(), nullptr, true, true,
|
||||||
|
true)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!mWebglValid) {
|
if (!mWebglValid) {
|
||||||
MarkSkiaChanged(aOptions);
|
MarkSkiaChanged(aOptions);
|
||||||
mSkia->FillRect(aRect, aPattern, aOptions);
|
mSkia->FillRect(aRect, aPattern, aOptions);
|
||||||
|
@ -2772,7 +2839,7 @@ void DrawTargetWebgl::Fill(const Path* aPath, const Pattern& aPattern,
|
||||||
const SkPath& skiaPath = static_cast<const PathSkia*>(aPath)->GetPath();
|
const SkPath& skiaPath = static_cast<const PathSkia*>(aPath)->GetPath();
|
||||||
SkRect skiaRect = SkRect::MakeEmpty();
|
SkRect skiaRect = SkRect::MakeEmpty();
|
||||||
// Draw the path as a simple rectangle with a supported pattern when possible.
|
// Draw the path as a simple rectangle with a supported pattern when possible.
|
||||||
if (skiaPath.isRect(&skiaRect) && SupportsPattern(aPattern)) {
|
if (skiaPath.isRect(&skiaRect)) {
|
||||||
RectDouble rect = SkRectToRectDouble(skiaRect);
|
RectDouble rect = SkRectToRectDouble(skiaRect);
|
||||||
RectDouble xformRect = TransformDouble(rect);
|
RectDouble xformRect = TransformDouble(rect);
|
||||||
if (aPattern.GetType() == PatternType::COLOR) {
|
if (aPattern.GetType() == PatternType::COLOR) {
|
||||||
|
@ -2784,9 +2851,21 @@ void DrawTargetWebgl::Fill(const Path* aPath, const Pattern& aPattern,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (RectInsidePrecisionLimits(xformRect)) {
|
if (RectInsidePrecisionLimits(xformRect)) {
|
||||||
DrawRect(NarrowToFloat(rect), aPattern, aOptions);
|
if (SupportsPattern(aPattern)) {
|
||||||
return;
|
DrawRect(NarrowToFloat(rect), aPattern, aOptions);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (aPattern.GetType() == PatternType::LINEAR_GRADIENT) {
|
||||||
|
if (Maybe<SurfacePattern> surface =
|
||||||
|
LinearGradientToSurface(xformRect, aPattern)) {
|
||||||
|
if (DrawRect(NarrowToFloat(rect), *surface, aOptions, Nothing(),
|
||||||
|
nullptr, true, true, true)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -619,6 +619,8 @@ class DrawTargetWebgl : public DrawTarget, public SupportsWeakPtr {
|
||||||
bool aTransformed = true, bool aClipped = true,
|
bool aTransformed = true, bool aClipped = true,
|
||||||
bool aAccelOnly = false, bool aForceUpdate = false,
|
bool aAccelOnly = false, bool aForceUpdate = false,
|
||||||
const StrokeOptions* aStrokeOptions = nullptr);
|
const StrokeOptions* aStrokeOptions = nullptr);
|
||||||
|
Maybe<SurfacePattern> LinearGradientToSurface(const RectDouble& aBounds,
|
||||||
|
const Pattern& aPattern);
|
||||||
|
|
||||||
ColorPattern GetClearPattern() const;
|
ColorPattern GetClearPattern() const;
|
||||||
|
|
||||||
|
|
|
@ -103,8 +103,8 @@ fuzzy(0-1,0-43) == 1201272-1.html 1201272-1-ref.html
|
||||||
== 1238795-1.html 1238795-1-ref.html
|
== 1238795-1.html 1238795-1-ref.html
|
||||||
== 1303534-1.html 1303534-1-ref.html
|
== 1303534-1.html 1303534-1-ref.html
|
||||||
|
|
||||||
fuzzy-if(cocoaWidget,0-1,0-1410) fuzzy-if(winWidget,0-1,0-1410) == 1304353-text-global-alpha-1.html 1304353-text-global-alpha-1-ref.html
|
fuzzy-if(cocoaWidget,0-1,0-1420) fuzzy-if(winWidget,0-1,0-1420) == 1304353-text-global-alpha-1.html 1304353-text-global-alpha-1-ref.html
|
||||||
fuzzy(0-1,0-1410) == 1304353-text-global-alpha-2.html 1304353-text-global-alpha-2-ref.html
|
fuzzy(0-1,0-1420) == 1304353-text-global-alpha-2.html 1304353-text-global-alpha-2-ref.html
|
||||||
fuzzy-if(winWidget,0-94,0-1575) fuzzy-if(cocoaWidget,0-1,0-34) == 1304353-text-global-composite-op-1.html 1304353-text-global-composite-op-1-ref.html
|
fuzzy-if(winWidget,0-94,0-1575) fuzzy-if(cocoaWidget,0-1,0-34) == 1304353-text-global-composite-op-1.html 1304353-text-global-composite-op-1-ref.html
|
||||||
|
|
||||||
== text-indent-1a.html text-indent-1-ref.html
|
== text-indent-1a.html text-indent-1-ref.html
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
fuzzy(0-4,0-89700) == linear-1a.html linear-1-ref.html
|
fuzzy(0-4,0-89700) == linear-1a.html linear-1-ref.html
|
||||||
fuzzy(0-2,0-23918) == linear-keywords-1a.html linear-keywords-1-ref.html
|
fuzzy(0-2,0-27600) == linear-keywords-1a.html linear-keywords-1-ref.html
|
||||||
== linear-diagonal-1a.html linear-diagonal-1-ref.html
|
== linear-diagonal-1a.html linear-diagonal-1-ref.html
|
||||||
== linear-diagonal-2a.html linear-diagonal-2-ref.html
|
== linear-diagonal-2a.html linear-diagonal-2-ref.html
|
||||||
== linear-diagonal-3a.html linear-diagonal-3-ref.html
|
== linear-diagonal-3a.html linear-diagonal-3-ref.html
|
||||||
|
|
Загрузка…
Ссылка в новой задаче