Home | History | Annotate | Download | only in graphics
      1 /*
      2  * Copyright (C) 2006, 2007, 2008, 2010 Apple Inc. All rights reserved.
      3  * Copyright (C) 2007 Alp Toker <alp (at) atoker.com>
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions
      7  * are met:
      8  * 1. Redistributions of source code must retain the above copyright
      9  *    notice, this list of conditions and the following disclaimer.
     10  * 2. Redistributions in binary form must reproduce the above copyright
     11  *    notice, this list of conditions and the following disclaimer in the
     12  *    documentation and/or other materials provided with the distribution.
     13  *
     14  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
     15  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     17  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
     18  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     19  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     20  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     21  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
     22  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     24  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     25  */
     26 
     27 #include "config.h"
     28 #include "Gradient.h"
     29 
     30 #include "Color.h"
     31 #include "FloatRect.h"
     32 #include <wtf/UnusedParam.h>
     33 
     34 namespace WebCore {
     35 
     36 Gradient::Gradient(const FloatPoint& p0, const FloatPoint& p1)
     37     : m_radial(false)
     38     , m_p0(p0)
     39     , m_p1(p1)
     40     , m_r0(0)
     41     , m_r1(0)
     42     , m_aspectRatio(1)
     43     , m_stopsSorted(false)
     44     , m_lastStop(0)
     45     , m_spreadMethod(SpreadMethodPad)
     46 {
     47     platformInit();
     48 }
     49 
     50 Gradient::Gradient(const FloatPoint& p0, float r0, const FloatPoint& p1, float r1, float aspectRatio)
     51     : m_radial(true)
     52     , m_p0(p0)
     53     , m_p1(p1)
     54     , m_r0(r0)
     55     , m_r1(r1)
     56     , m_aspectRatio(aspectRatio)
     57     , m_stopsSorted(false)
     58     , m_lastStop(0)
     59     , m_spreadMethod(SpreadMethodPad)
     60 {
     61     platformInit();
     62 }
     63 
     64 Gradient::~Gradient()
     65 {
     66     platformDestroy();
     67 }
     68 
     69 void Gradient::adjustParametersForTiledDrawing(IntSize& size, FloatRect& srcRect)
     70 {
     71     if (m_radial)
     72         return;
     73 
     74     if (srcRect.isEmpty())
     75         return;
     76 
     77     if (m_p0.x() == m_p1.x()) {
     78         size.setWidth(1);
     79         srcRect.setWidth(1);
     80         srcRect.setX(0);
     81         return;
     82     }
     83     if (m_p0.y() != m_p1.y())
     84         return;
     85 
     86     size.setHeight(1);
     87     srcRect.setHeight(1);
     88     srcRect.setY(0);
     89 }
     90 
     91 void Gradient::addColorStop(float value, const Color& color)
     92 {
     93     float r;
     94     float g;
     95     float b;
     96     float a;
     97     color.getRGBA(r, g, b, a);
     98     m_stops.append(ColorStop(value, r, g, b, a));
     99 
    100     m_stopsSorted = false;
    101     platformDestroy();
    102 }
    103 
    104 void Gradient::addColorStop(const Gradient::ColorStop& stop)
    105 {
    106     m_stops.append(stop);
    107 
    108     m_stopsSorted = false;
    109     platformDestroy();
    110 }
    111 
    112 static inline bool compareStops(const Gradient::ColorStop& a, const Gradient::ColorStop& b)
    113 {
    114     return a.stop < b.stop;
    115 }
    116 
    117 void Gradient::sortStopsIfNecessary()
    118 {
    119     if (m_stopsSorted)
    120         return;
    121 
    122     m_stopsSorted = true;
    123 
    124     if (!m_stops.size())
    125         return;
    126 
    127     // Shortcut for the ideal case (ordered 2-stop gradient)
    128     if (m_stops.size() == 2 && compareStops(*m_stops.begin(), *m_stops.end()))
    129         return;
    130 
    131     std::stable_sort(m_stops.begin(), m_stops.end(), compareStops);
    132 }
    133 
    134 void Gradient::getColor(float value, float* r, float* g, float* b, float* a) const
    135 {
    136     ASSERT(value >= 0);
    137     ASSERT(value <= 1);
    138 
    139     if (m_stops.isEmpty()) {
    140         *r = 0;
    141         *g = 0;
    142         *b = 0;
    143         *a = 0;
    144         return;
    145     }
    146     if (!m_stopsSorted) {
    147         if (m_stops.size())
    148             std::stable_sort(m_stops.begin(), m_stops.end(), compareStops);
    149         m_stopsSorted = true;
    150     }
    151     if (value <= 0 || value <= m_stops.first().stop) {
    152         *r = m_stops.first().red;
    153         *g = m_stops.first().green;
    154         *b = m_stops.first().blue;
    155         *a = m_stops.first().alpha;
    156         return;
    157     }
    158     if (value >= 1 || value >= m_stops.last().stop) {
    159         *r = m_stops.last().red;
    160         *g = m_stops.last().green;
    161         *b = m_stops.last().blue;
    162         *a = m_stops.last().alpha;
    163         return;
    164     }
    165 
    166     // Find stop before and stop after and interpolate.
    167     int stop = findStop(value);
    168     const ColorStop& lastStop = m_stops[stop];
    169     const ColorStop& nextStop = m_stops[stop + 1];
    170     float stopFraction = (value - lastStop.stop) / (nextStop.stop - lastStop.stop);
    171     *r = lastStop.red + (nextStop.red - lastStop.red) * stopFraction;
    172     *g = lastStop.green + (nextStop.green - lastStop.green) * stopFraction;
    173     *b = lastStop.blue + (nextStop.blue - lastStop.blue) * stopFraction;
    174     *a = lastStop.alpha + (nextStop.alpha - lastStop.alpha) * stopFraction;
    175 }
    176 
    177 int Gradient::findStop(float value) const
    178 {
    179     ASSERT(value >= 0);
    180     ASSERT(value <= 1);
    181     ASSERT(m_stopsSorted);
    182 
    183     int numStops = m_stops.size();
    184     ASSERT(numStops >= 2);
    185     ASSERT(m_lastStop < numStops - 1);
    186 
    187     int i = m_lastStop;
    188     if (value < m_stops[i].stop)
    189         i = 1;
    190     else
    191         i = m_lastStop + 1;
    192 
    193     for (; i < numStops - 1; ++i)
    194         if (value < m_stops[i].stop)
    195             break;
    196 
    197     m_lastStop = i - 1;
    198     return m_lastStop;
    199 }
    200 
    201 bool Gradient::hasAlpha() const
    202 {
    203     for (size_t i = 0; i < m_stops.size(); i++) {
    204         if (m_stops[i].alpha < 1)
    205             return true;
    206     }
    207 
    208     return false;
    209 }
    210 
    211 void Gradient::setSpreadMethod(GradientSpreadMethod spreadMethod)
    212 {
    213     // FIXME: Should it become necessary, allow calls to this method after m_gradient has been set.
    214     ASSERT(m_gradient == 0);
    215     m_spreadMethod = spreadMethod;
    216 }
    217 
    218 void Gradient::setGradientSpaceTransform(const AffineTransform& gradientSpaceTransformation)
    219 {
    220     m_gradientSpaceTransformation = gradientSpaceTransformation;
    221     setPlatformGradientSpaceTransform(gradientSpaceTransformation);
    222 }
    223 
    224 #if !USE(SKIA) && !USE(CAIRO)
    225 void Gradient::setPlatformGradientSpaceTransform(const AffineTransform&)
    226 {
    227 }
    228 #endif
    229 
    230 
    231 } //namespace
    232