Home | History | Annotate | Download | only in css
      1 /*
      2  * Copyright (C) 2008 Apple Inc.  All rights reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions
      6  * are met:
      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.
     12  *
     13  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, 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 COMPUTER, 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.
     24  */
     25 
     26 #include "config.h"
     27 #include "CSSGradientValue.h"
     28 
     29 #include "CSSStyleSelector.h"
     30 #include "GeneratedImage.h"
     31 #include "Gradient.h"
     32 #include "Image.h"
     33 #include "IntSize.h"
     34 #include "IntSizeHash.h"
     35 #include "PlatformString.h"
     36 #include "RenderObject.h"
     37 
     38 using namespace std;
     39 
     40 namespace WebCore {
     41 
     42 String CSSGradientValue::cssText() const
     43 {
     44     String result = "-webkit-gradient(";
     45     if (m_type == CSSLinearGradient)
     46         result += "linear, ";
     47     else
     48         result += "radial, ";
     49     result += m_firstX->cssText() + " ";
     50     result += m_firstY->cssText() + ", ";
     51     if (m_type == CSSRadialGradient)
     52         result += m_firstRadius->cssText() + ", ";
     53     result += m_secondX->cssText() + " ";
     54     result += m_secondY->cssText();
     55     if (m_type == CSSRadialGradient) {
     56         result += ", ";
     57         result += m_secondRadius->cssText();
     58     }
     59     for (unsigned i = 0; i < m_stops.size(); i++) {
     60         result += ", ";
     61         if (m_stops[i].m_stop == 0)
     62             result += "from(" + m_stops[i].m_color->cssText() + ")";
     63         else if (m_stops[i].m_stop == 1)
     64             result += "to(" + m_stops[i].m_color->cssText() + ")";
     65         else
     66             result += "color-stop(" + String::number(m_stops[i].m_stop) + ", " + m_stops[i].m_color->cssText() + ")";
     67     }
     68     result += ")";
     69     return result;
     70 }
     71 
     72 PassRefPtr<Gradient> CSSGradientValue::createGradient(RenderObject* renderer, const IntSize& size)
     73 {
     74     ASSERT(!size.isEmpty());
     75 
     76     float zoomFactor = renderer->style()->effectiveZoom();
     77 
     78     FloatPoint firstPoint = resolvePoint(m_firstX.get(), m_firstY.get(), size, zoomFactor);
     79     FloatPoint secondPoint = resolvePoint(m_secondX.get(), m_secondY.get(), size, zoomFactor);
     80 
     81     RefPtr<Gradient> gradient;
     82     if (m_type == CSSLinearGradient)
     83         gradient = Gradient::create(firstPoint, secondPoint);
     84     else {
     85         float firstRadius = resolveRadius(m_firstRadius.get(), zoomFactor);
     86         float secondRadius = resolveRadius(m_secondRadius.get(), zoomFactor);
     87         gradient = Gradient::create(firstPoint, firstRadius, secondPoint, secondRadius);
     88     }
     89 
     90     // Now add the stops.
     91     sortStopsIfNeeded();
     92 
     93     // We have to resolve colors.
     94     for (unsigned i = 0; i < m_stops.size(); i++) {
     95         Color color = renderer->document()->styleSelector()->getColorFromPrimitiveValue(m_stops[i].m_color.get());
     96         gradient->addColorStop(m_stops[i].m_stop, color);
     97     }
     98 
     99     // The back end already sorted the stops.
    100     gradient->setStopsSorted(true);
    101 
    102     return gradient.release();
    103 }
    104 
    105 Image* CSSGradientValue::image(RenderObject* renderer, const IntSize& size)
    106 {
    107     ASSERT(m_clients.contains(renderer));
    108 
    109     // Need to look up our size.  Create a string of width*height to use as a hash key.
    110     Image* result = getImage(renderer, size);
    111     if (result)
    112         return result;
    113 
    114     if (size.isEmpty())
    115         return 0;
    116 
    117     // We need to create an image.
    118     RefPtr<Image> newImage = GeneratedImage::create(createGradient(renderer, size), size);
    119     result = newImage.get();
    120     putImage(size, newImage.release());
    121 
    122     return result;
    123 }
    124 
    125 static inline bool compareStops(const CSSGradientColorStop& a, const CSSGradientColorStop& b)
    126 {
    127     return a.m_stop < b.m_stop;
    128 }
    129 
    130 void CSSGradientValue::sortStopsIfNeeded()
    131 {
    132     if (!m_stopsSorted) {
    133         if (m_stops.size())
    134             std::stable_sort(m_stops.begin(), m_stops.end(), compareStops);
    135         m_stopsSorted = true;
    136     }
    137 }
    138 
    139 FloatPoint CSSGradientValue::resolvePoint(CSSPrimitiveValue* first, CSSPrimitiveValue* second, const IntSize& size, float zoomFactor)
    140 {
    141     FloatPoint result;
    142     if (first->primitiveType() == CSSPrimitiveValue::CSS_NUMBER)
    143         result.setX(first->getFloatValue() * zoomFactor);
    144     else if (first->primitiveType() == CSSPrimitiveValue::CSS_PERCENTAGE)
    145         result.setX(first->getFloatValue() / 100.f * size.width());
    146     if (second->primitiveType() == CSSPrimitiveValue::CSS_NUMBER)
    147         result.setY(second->getFloatValue() * zoomFactor);
    148     else if (second->primitiveType() == CSSPrimitiveValue::CSS_PERCENTAGE)
    149         result.setY(second->getFloatValue() / 100.f * size.height());
    150 
    151     return result;
    152 }
    153 
    154 float CSSGradientValue::resolveRadius(CSSPrimitiveValue* radius, float zoomFactor)
    155 {
    156     float result = 0.f;
    157     if (radius->primitiveType() == CSSPrimitiveValue::CSS_NUMBER)
    158         result = radius->getFloatValue() * zoomFactor;
    159     return result;
    160 }
    161 
    162 } // namespace WebCore
    163