gecko-dev/layout/painting/nsCSSRenderingGradients.h

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

190 lines
7.4 KiB
C
Raw Normal View History

/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef nsCSSRenderingGradients_h__
#define nsCSSRenderingGradients_h__
Bug 1754315: Fix non-unified build errors in layout/painting, and mark it as safe to build in non-unified mode. r=boris Build errors fixed here: layout/painting/DottedCornerFinder.cpp:33:1: error: no template named 'nsTHashMap' (and similar for layout/painting/DashedCornerFinder.cpp) * Fixed by including nsTHashMap.h layout/painting/WindowRenderer.cpp:186:38: error: use of undeclared identifier 'Rect'; did you mean 'gfx::Rect'? layout/painting/WindowRenderer.cpp:111:18: error: unknown type name 'PersistentBufferProvider'; did you mean 'layers::PersistentBufferProvider'? (and more similar errors for e.g. `PersistentBufferProviderBasic::Create`, etc.) * Fixed by adding 'using' statements. layout/painting/WindowRenderer.cpp:117:8: error: use of undeclared identifier 'gfxPlatform' layout/painting/WindowRenderer.cpp:148:57: error: member access into incomplete type 'mozilla::dom::AnimationEffect' layout/painting/WindowRenderer.cpp:150:16: error: incomplete type 'mozilla::EffectSet' named in nested name specifier layout/painting/WindowRenderer.cpp:211:26: error: member access into incomplete type 'mozilla::nsDisplayList' * Fixed by including these types' headers. layout/painting/HitTestInfo.cpp:67:32: error: use of undeclared identifier 'CompositorHitTestFlags'; did you mean 'gfx::CompositorHitTestFlags'? * Fixed by adding 'using' statement. layout/painting/nsCSSRenderingGradients.cpp:772:26: error: incomplete type 'nsLayoutUtils' named in nested name specifier * Fixed by including nsLayoutUtils.h layout/painting/nsCSSRenderingGradients.h:106:29: error: unknown type name 'gfxPattern' * Fixed with a forward-decl. layout/painting/nsCSSRenderingGradients.h:107:30: error: unknown type name 'gfxRect' * Fixed with an include (can't use a forward-decl here; gfxRect is a typedef and hence can't really be forward-declared). Differential Revision: https://phabricator.services.mozilla.com/D138219
2022-02-09 01:06:29 +00:00
#include "gfxRect.h"
#include "gfxUtils.h"
#include "nsStyleStruct.h"
#include "Units.h"
#include "mozilla/Maybe.h"
#include "mozilla/gfx/2D.h"
#include "mozilla/webrender/webrender_ffi.h"
Bug 1754315: Fix non-unified build errors in layout/painting, and mark it as safe to build in non-unified mode. r=boris Build errors fixed here: layout/painting/DottedCornerFinder.cpp:33:1: error: no template named 'nsTHashMap' (and similar for layout/painting/DashedCornerFinder.cpp) * Fixed by including nsTHashMap.h layout/painting/WindowRenderer.cpp:186:38: error: use of undeclared identifier 'Rect'; did you mean 'gfx::Rect'? layout/painting/WindowRenderer.cpp:111:18: error: unknown type name 'PersistentBufferProvider'; did you mean 'layers::PersistentBufferProvider'? (and more similar errors for e.g. `PersistentBufferProviderBasic::Create`, etc.) * Fixed by adding 'using' statements. layout/painting/WindowRenderer.cpp:117:8: error: use of undeclared identifier 'gfxPlatform' layout/painting/WindowRenderer.cpp:148:57: error: member access into incomplete type 'mozilla::dom::AnimationEffect' layout/painting/WindowRenderer.cpp:150:16: error: incomplete type 'mozilla::EffectSet' named in nested name specifier layout/painting/WindowRenderer.cpp:211:26: error: member access into incomplete type 'mozilla::nsDisplayList' * Fixed by including these types' headers. layout/painting/HitTestInfo.cpp:67:32: error: use of undeclared identifier 'CompositorHitTestFlags'; did you mean 'gfx::CompositorHitTestFlags'? * Fixed by adding 'using' statement. layout/painting/nsCSSRenderingGradients.cpp:772:26: error: incomplete type 'nsLayoutUtils' named in nested name specifier * Fixed by including nsLayoutUtils.h layout/painting/nsCSSRenderingGradients.h:106:29: error: unknown type name 'gfxPattern' * Fixed with a forward-decl. layout/painting/nsCSSRenderingGradients.h:107:30: error: unknown type name 'gfxRect' * Fixed with an include (can't use a forward-decl here; gfxRect is a typedef and hence can't really be forward-declared). Differential Revision: https://phabricator.services.mozilla.com/D138219
2022-02-09 01:06:29 +00:00
class gfxPattern;
namespace mozilla {
namespace layers {
class StackingContextHelper;
} // namespace layers
namespace wr {
class DisplayListBuilder;
} // namespace wr
// A resolved color stop, with a specific position along the gradient line and
// a color.
struct ColorStop {
ColorStop() : mPosition(0), mIsMidpoint(false) {}
ColorStop(double aPosition, bool aIsMidPoint,
const StyleAbsoluteColor& aColor)
: mPosition(aPosition), mIsMidpoint(aIsMidPoint), mColor(aColor) {}
double mPosition; // along the gradient line; 0=start, 1=end
bool mIsMidpoint;
StyleAbsoluteColor mColor;
};
template <class T>
class MOZ_STACK_CLASS ColorStopInterpolator {
public:
ColorStopInterpolator(
const nsTArray<ColorStop>& aStops,
const StyleColorInterpolationMethod& aStyleColorInterpolationMethod,
bool aExtendLastStop)
: mStyleColorInterpolationMethod(aStyleColorInterpolationMethod),
mStops(aStops),
mExtendLastStop(aExtendLastStop) {}
void CreateStops() {
// This loop intentionally iterates the last stop if extending.
uint32_t iterStops = mStops.Length() - (mExtendLastStop ? 0 : 1);
for (uint32_t i = 0; i < iterStops; i++) {
auto nextindex = i + 1 < mStops.Length() ? i + 1 : i;
const auto& start = mStops[i];
const auto& end = mStops[nextindex];
float startPosition = start.mPosition;
float endPosition = end.mPosition;
// For CSS non-repeating gradients with longer hue specified, we have to
// pretend there is a stop beyond the last stop. This is never the case
// on SVG gradients as they only use shorter hue.
//
// See https://bugzilla.mozilla.org/show_bug.cgi?id=1885716 for more info.
if (i == mStops.Length() - 1 && mExtendLastStop) {
endPosition = 1.0f;
}
uint32_t extraStops =
(uint32_t)(floor(endPosition * kFullRangeExtraStops) -
floor(startPosition * kFullRangeExtraStops));
extraStops = clamped(extraStops, 1U, kFullRangeExtraStops);
float step = 1.0f / (float)extraStops;
for (uint32_t extraStop = 0; extraStop <= extraStops; extraStop++) {
auto progress = (float)extraStop * step;
auto position =
startPosition + progress * (endPosition - startPosition);
StyleAbsoluteColor color =
Servo_InterpolateColor(mStyleColorInterpolationMethod, &end.mColor,
&start.mColor, progress);
static_cast<T*>(this)->CreateStop(float(position),
gfx::ToDeviceColor(color));
}
}
}
protected:
StyleColorInterpolationMethod mStyleColorInterpolationMethod;
const nsTArray<ColorStop>& mStops;
// This indicates that we want to extend the endPosition on the last stop,
// which only matters if this is a CSS non-repeating gradient with
// StyleHueInterpolationMethod::Longer (only valid for hsl/hwb/lch/oklch).
bool mExtendLastStop;
// This could be made tunable, but at 1.0/128 the error is largely
// irrelevant, as WebRender re-encodes it to 128 pairs of stops.
//
// Note that we don't attempt to place the positions of these stops
// precisely at intervals, we just add this many extra stops across the
// range where it is convenient.
inline static const uint32_t kFullRangeExtraStops = 128;
};
class nsCSSGradientRenderer final {
public:
/**
* Prepare a nsCSSGradientRenderer for a gradient for an element.
* aIntrinsicSize - the size of the source gradient.
*/
static nsCSSGradientRenderer Create(nsPresContext* aPresContext,
ComputedStyle* aComputedStyle,
const StyleGradient& aGradient,
const nsSize& aIntrinsiceSize);
/**
* Draw the gradient to aContext
* aDest - where the first tile of gradient is
* aFill - the area to be filled with tiles of aDest
* aSrc - the area of the gradient that will fill aDest
* aRepeatSize - the distance from the origin of a tile
* to the next origin of a tile
* aDirtyRect - pixels outside of this area may be skipped
*/
void Paint(gfxContext& aContext, const nsRect& aDest, const nsRect& aFill,
const nsSize& aRepeatSize, const mozilla::CSSIntRect& aSrc,
const nsRect& aDirtyRect, float aOpacity = 1.0);
/**
* Collect the gradient parameters
*/
void BuildWebRenderParameters(float aOpacity, wr::ExtendMode& aMode,
nsTArray<wr::GradientStop>& aStops,
LayoutDevicePoint& aLineStart,
LayoutDevicePoint& aLineEnd,
LayoutDeviceSize& aGradientRadius,
LayoutDevicePoint& aGradientCenter,
float& aGradientAngle);
/**
* Build display items for the gradient
* aLayer - the layer to make this display item relative to
* aDest - where the first tile of gradient is
* aFill - the area to be filled with tiles of aDest
* aRepeatSize - the distance from the origin of a tile
* to the next origin of a tile
* aSrc - the area of the gradient that will fill aDest
*/
void BuildWebRenderDisplayItems(wr::DisplayListBuilder& aBuilder,
const layers::StackingContextHelper& aSc,
const nsRect& aDest, const nsRect& aFill,
const nsSize& aRepeatSize,
const mozilla::CSSIntRect& aSrc,
bool aIsBackfaceVisible,
float aOpacity = 1.0);
private:
nsCSSGradientRenderer()
: mPresContext(nullptr),
mGradient(nullptr),
mRadiusX(0.0),
mRadiusY(0.0),
mAngle(0.0) {}
/**
* Attempts to paint the tiles for a gradient by painting it once to an
* offscreen surface and then painting that offscreen surface with
* ExtendMode::Repeat to cover all tiles.
*
* Returns false if the optimization wasn't able to be used, in which case
* a fallback should be used.
*/
bool TryPaintTilesWithExtendMode(
gfxContext& aContext, gfxPattern* aGradientPattern, nscoord aXStart,
nscoord aYStart, const gfxRect& aDirtyAreaToFill, const nsRect& aDest,
const nsSize& aRepeatSize, bool aForceRepeatToCoverTiles);
nsPresContext* mPresContext;
const StyleGradient* mGradient;
nsTArray<ColorStop> mStops;
gfxPoint mLineStart, mLineEnd; // only for linear/radial gradients
double mRadiusX, mRadiusY; // only for radial gradients
gfxPoint mCenter; // only for conic gradients
float mAngle; // only for conic gradients
};
} // namespace mozilla
#endif /* nsCSSRenderingGradients_h__ */