mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-12-26 10:10:31 +00:00
Bug 1074056 - Part 2 - Rendering part of 1074056: Add support for interpolation hints to CSS gradients. r=roc
This commit is contained in:
parent
85aa244222
commit
3da0db254e
@ -350,9 +350,11 @@ protected:
|
||||
// A resolved color stop --- with a specific position along the gradient line,
|
||||
// and a Thebes color
|
||||
struct ColorStop {
|
||||
ColorStop(double aPosition, gfxRGBA aColor) :
|
||||
mPosition(aPosition), mColor(aColor) {}
|
||||
ColorStop(): mPosition(0), mIsMidpoint(false) {}
|
||||
ColorStop(double aPosition, bool aIsMidPoint, gfxRGBA aColor) :
|
||||
mPosition(aPosition), mIsMidpoint(aIsMidPoint), mColor(aColor) {}
|
||||
double mPosition; // along the gradient line; 0=start, 1=end
|
||||
bool mIsMidpoint;
|
||||
gfxRGBA mColor;
|
||||
};
|
||||
|
||||
@ -2233,6 +2235,84 @@ RectIsBeyondLinearGradientEdge(const gfxRect& aRect,
|
||||
return false;
|
||||
}
|
||||
|
||||
static void ResolveMidpoints(nsTArray<ColorStop>& stops)
|
||||
{
|
||||
for (size_t x = 1; x < stops.Length() - 1;) {
|
||||
if (!stops[x].mIsMidpoint) {
|
||||
x++;
|
||||
continue;
|
||||
}
|
||||
|
||||
gfxRGBA color1 = stops[x-1].mColor;
|
||||
gfxRGBA color2 = stops[x+1].mColor;
|
||||
float offset1 = stops[x-1].mPosition;
|
||||
float offset2 = stops[x+1].mPosition;
|
||||
float offset = stops[x].mPosition;
|
||||
// check if everything coincides. If so, ignore the midpoint.
|
||||
if (offset - offset1 == offset2 - offset) {
|
||||
stops.RemoveElementAt(x);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check if we coincide with the left colorstop.
|
||||
if (offset1 == offset) {
|
||||
// Morph the midpoint to a regular stop with the color of the next
|
||||
// color stop.
|
||||
stops[x].mColor = color2;
|
||||
stops[x].mIsMidpoint = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check if we coincide with the right colorstop.
|
||||
if (offset2 == offset) {
|
||||
// Morph the midpoint to a regular stop with the color of the previous
|
||||
// color stop.
|
||||
stops[x].mColor = color1;
|
||||
stops[x].mIsMidpoint = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
float midpoint = (offset - offset1) / (offset2 - offset1);
|
||||
ColorStop newStops[9];
|
||||
if (midpoint > .5f) {
|
||||
for (size_t y = 0; y < 7; y++) {
|
||||
newStops[y].mPosition = offset1 + (offset - offset1) * (7 + y) / 13;
|
||||
}
|
||||
|
||||
newStops[7].mPosition = offset + (offset2 - offset) / 3;
|
||||
newStops[8].mPosition = offset + (offset2 - offset) * 2 / 3;
|
||||
} else {
|
||||
newStops[0].mPosition = offset1 + (offset - offset1) / 3;
|
||||
newStops[1].mPosition = offset1 + (offset - offset1) * 2 / 3;
|
||||
|
||||
for (size_t y = 0; y < 7; y++) {
|
||||
newStops[y+2].mPosition = offset + (offset2 - offset) * y / 13;
|
||||
}
|
||||
}
|
||||
// calculate colors
|
||||
|
||||
for (size_t y = 0; y < 9; y++) {
|
||||
// Calculate the intermediate color stops per the formula of the CSS images
|
||||
// spec. http://dev.w3.org/csswg/css-images/#color-stop-syntax
|
||||
// 9 points were chosen since it is the minimum number of stops that always
|
||||
// give the smoothest appearace regardless of midpoint position and difference
|
||||
// in luminance of the end points.
|
||||
float relativeOffset = (newStops[y].mPosition - offset1) / (offset2 - offset1);
|
||||
float multiplier = powf(relativeOffset, logf(.5f) / logf(midpoint));
|
||||
|
||||
gfxFloat red = color1.r + multiplier * (color2.r - color1.r);
|
||||
gfxFloat green = color1.g + multiplier * (color2.g - color1.g);
|
||||
gfxFloat blue = color1.b + multiplier * (color2.b - color1.b);
|
||||
gfxFloat alpha = color1.a + multiplier * (color2.a - color1.a);
|
||||
|
||||
newStops[y].mColor = gfxRGBA(red, green, blue, alpha);
|
||||
}
|
||||
|
||||
stops.ReplaceElementsAt(x, 1, newStops, 9);
|
||||
x += 9;
|
||||
}
|
||||
}
|
||||
|
||||
static gfxRGBA
|
||||
Premultiply(const gfxRGBA& aColor)
|
||||
{
|
||||
@ -2295,7 +2375,7 @@ ResolvePremultipliedAlpha(nsTArray<ColorStop>& aStops)
|
||||
size_t stepCount = NSToIntFloor(fabs(leftStop.mColor.a - rightStop.mColor.a) / kAlphaIncrementPerGradientStep);
|
||||
for (size_t y = 1; y < stepCount; y++) {
|
||||
float frac = static_cast<float>(y) / stepCount;
|
||||
ColorStop newStop(Interpolate(leftStop.mPosition, rightStop.mPosition, frac),
|
||||
ColorStop newStop(Interpolate(leftStop.mPosition, rightStop.mPosition, frac), false,
|
||||
Unpremultiply(InterpolateColor(premulLeftColor, premulRightColor, frac)));
|
||||
aStops.InsertElementAt(x, newStop);
|
||||
x++;
|
||||
@ -2371,7 +2451,7 @@ nsCSSRendering::PaintGradient(nsPresContext* aPresContext,
|
||||
if (firstUnsetPosition < 0) {
|
||||
firstUnsetPosition = i;
|
||||
}
|
||||
stops.AppendElement(ColorStop(0, stop.mColor));
|
||||
stops.AppendElement(ColorStop(0, stop.mIsInterpolationHint, stop.mColor));
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
@ -2398,7 +2478,7 @@ nsCSSRendering::PaintGradient(nsPresContext* aPresContext,
|
||||
// to the previous stop position, if necessary
|
||||
position = std::max(position, stops[i - 1].mPosition);
|
||||
}
|
||||
stops.AppendElement(ColorStop(position, stop.mColor));
|
||||
stops.AppendElement(ColorStop(position, stop.mIsInterpolationHint, stop.mColor));
|
||||
if (firstUnsetPosition > 0) {
|
||||
// Interpolate positions for all stops that didn't have a specified position
|
||||
double p = stops[firstUnsetPosition - 1].mPosition;
|
||||
@ -2593,11 +2673,12 @@ nsCSSRendering::PaintGradient(nsPresContext* aPresContext,
|
||||
stops.Clear();
|
||||
|
||||
if (!aGradient->mRepeating && !zeroRadius) {
|
||||
stops.AppendElement(ColorStop(firstStop, firstColor));
|
||||
stops.AppendElement(ColorStop(firstStop, false, firstColor));
|
||||
}
|
||||
stops.AppendElement(ColorStop(firstStop, lastColor));
|
||||
stops.AppendElement(ColorStop(firstStop, false, lastColor));
|
||||
}
|
||||
|
||||
ResolveMidpoints(stops);
|
||||
ResolvePremultipliedAlpha(stops);
|
||||
|
||||
bool isRepeat = aGradient->mRepeating || forceRepeatToCoverTiles;
|
||||
|
Loading…
Reference in New Issue
Block a user