2 * Copyright (C) 2016 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 #include "FloatPoint.h"
30 #include "GraphicsContext.h"
32 #include <wtf/RetainPtr.h>
34 #define GRADIENT_DRAWING 3
38 void Gradient::platformDestroy()
41 m_gradient->Release();
45 ID2D1Brush* Gradient::platformGradient()
51 ID2D1Brush* Gradient::createPlatformGradientIfNecessary(ID2D1RenderTarget* context)
53 generateGradient(context);
57 void Gradient::generateGradient(ID2D1RenderTarget* renderTarget)
59 sortStopsIfNecessary();
61 Vector<D2D1_GRADIENT_STOP> gradientStops;
62 // FIXME: Add support for ExtendedColor.
63 for (auto stop : m_stops) {
68 stop.color.getRGBA(r, g, b, a);
69 gradientStops.append(D2D1::GradientStop(stop.offset, D2D1::ColorF(r, g, b, a)));
72 COMPtr<ID2D1GradientStopCollection> gradientStopCollection;
73 HRESULT hr = renderTarget->CreateGradientStopCollection(gradientStops.data(), gradientStops.size(), &gradientStopCollection);
74 RELEASE_ASSERT(SUCCEEDED(hr));
77 m_gradient->Release();
82 [&] (const LinearData& data) {
83 ID2D1LinearGradientBrush* linearGradient = nullptr;
84 hr = renderTarget->CreateLinearGradientBrush(
85 D2D1::LinearGradientBrushProperties(data.point0, data.point1),
86 D2D1::BrushProperties(), gradientStopCollection.get(),
88 RELEASE_ASSERT(SUCCEEDED(hr));
89 m_gradient = linearGradient;
91 [&] (const RadialData& data) {
92 FloatSize offset = data.point1 - data.point0;
93 ID2D1RadialGradientBrush* radialGradient = nullptr;
94 float radiusX = data.endRadius + offset.width();
95 float radiusY = radiusX / data.aspectRatio;
96 hr = renderTarget->CreateRadialGradientBrush(
97 D2D1::RadialGradientBrushProperties(p0(), D2D1::Point2F(offset.width(), offset.height()), radiusX, radiusY),
98 D2D1::BrushProperties(), gradientStopCollection.get(),
100 RELEASE_ASSERT(SUCCEEDED(hr));
101 m_gradient = radialGradient;
108 void Gradient::fill(GraphicsContext& context, const FloatRect& rect)
110 auto d2dContext = context.platformContext();
112 WTF::switchOn(m_data,
113 [&] (const LinearData& data) {
114 if (!m_cachedHash || !m_gradient)
115 generateGradient(d2dContext);
117 d2dContext->SetTags(GRADIENT_DRAWING, __LINE__);
119 const D2D1_RECT_F d2dRect = rect;
120 d2dContext->FillRectangle(&d2dRect, m_gradient);
122 [&] (const RadialData& data) {
123 bool needScaling = data.aspectRatio != 1;
126 // Scale from the center of the gradient. We only ever scale non-deprecated gradients,
127 // for which m_p0 == m_p1.
128 ASSERT(data.point0 == data.point1);
130 D2D1_MATRIX_3X2_F ctm = { };
131 d2dContext->GetTransform(&ctm);
133 AffineTransform transform(ctm);
134 transform.translate(data.point0);
135 transform.scaleNonUniform(1.0, 1.0 / data.aspectRatio);
136 transform.translate(-data.point0);
138 d2dContext->SetTransform(ctm);
141 if (!m_cachedHash || !m_gradient)
142 generateGradient(d2dContext);
144 d2dContext->SetTags(GRADIENT_DRAWING, __LINE__);
146 const D2D1_RECT_F d2dRect = rect;
147 d2dContext->FillRectangle(&d2dRect, m_gradient);