1/*
2 * Copyright (C) 2011 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 "CrossfadeGeneratedImage.h"
28
29#include "CSSCrossfadeValue.h"
30#include "FloatRect.h"
31#include "GraphicsContext.h"
32#include "ImageBuffer.h"
33
34using namespace std;
35
36namespace WebCore {
37
38CrossfadeGeneratedImage::CrossfadeGeneratedImage(CachedImage* fromImage, CachedImage* toImage, float percentage, ImageObserver* observer, const IntSize& size)
39 : m_fromImage(fromImage)
40 , m_toImage(toImage)
41 , m_percentage(percentage)
42 , m_observer(observer)
43 , m_crossfadeSubimageObserver(adoptPtr(new CrossfadeSubimageObserverProxy(this)))
44{
45 m_size = size;
46
47 m_fromImage->addClient(m_crossfadeSubimageObserver.get());
48 m_toImage->addClient(m_crossfadeSubimageObserver.get());
49
50 m_crossfadeSubimageObserver->setReady(true);
51}
52
53CrossfadeGeneratedImage::~CrossfadeGeneratedImage()
54{
55 m_fromImage->removeClient(m_crossfadeSubimageObserver.get());
56 m_toImage->removeClient(m_crossfadeSubimageObserver.get());
57}
58
59void CrossfadeGeneratedImage::drawCrossfade(GraphicsContext* context)
60{
61 Image* fromImage = 0;
62 Image* toImage = 0;
63 IntSize fromImageSize, toImageSize, crossfadeImageSize;
64 float inversePercentage = 1.0f - m_percentage;
65
66 fromImage = m_fromImage->image();
67 fromImageSize = fromImage->size();
68 toImage = m_toImage->image();
69 toImageSize = toImage->size();
70
71 // Draw nothing if either of the images hasn't loaded yet.
72 if (fromImage == Image::nullImage() || toImage == Image::nullImage())
73 return;
74
75 crossfadeImageSize = IntSize(fromImageSize.width() * inversePercentage + toImageSize.width() * m_percentage,
76 fromImageSize.height() * inversePercentage + toImageSize.height() * m_percentage);
77
78 GraphicsContextStateSaver stateSaver(*context);
79
80 // Draw the image we're fading away from.
81 context->save();
82 if (crossfadeImageSize != fromImageSize)
83 context->scale(FloatSize(static_cast<float>(crossfadeImageSize.width()) / fromImageSize.width(),
84 static_cast<float>(crossfadeImageSize.height()) / fromImageSize.height()));
85 context->setAlpha(inversePercentage);
86 context->drawImage(fromImage, ColorSpaceDeviceRGB, IntPoint());
87 context->restore();
88
89 // Draw the image we're fading towards.
90 context->save();
91 if (crossfadeImageSize != toImageSize)
92 context->scale(FloatSize(static_cast<float>(crossfadeImageSize.width()) / toImageSize.width(),
93 static_cast<float>(crossfadeImageSize.height()) / toImageSize.height()));
94 context->setCompositeOperation(CompositeSourceOver);
95 context->setAlpha(m_percentage);
96 context->drawImage(toImage, ColorSpaceDeviceRGB, IntPoint());
97 context->restore();
98}
99
100void CrossfadeGeneratedImage::draw(GraphicsContext* context, const FloatRect& dstRect, const FloatRect& srcRect, ColorSpace, CompositeOperator compositeOp)
101{
102 UNUSED_PARAM(compositeOp);
103 UNUSED_PARAM(srcRect);
104
105 GraphicsContextStateSaver stateSaver(*context);
106 context->clip(dstRect);
107 context->translate(dstRect.x(), dstRect.y());
108
109 drawCrossfade(context);
110}
111
112void CrossfadeGeneratedImage::drawPattern(GraphicsContext* context, const FloatRect& srcRect, const AffineTransform& patternTransform, const FloatPoint& phase, ColorSpace styleColorSpace, CompositeOperator compositeOp, const FloatRect& destRect)
113{
114 OwnPtr<ImageBuffer> imageBuffer = ImageBuffer::create(m_size);
115 if (!imageBuffer)
116 return;
117
118 // Fill with the cross-faded image.
119 GraphicsContext* graphicsContext = imageBuffer->context();
120 drawCrossfade(graphicsContext);
121
122 // Tile the image buffer into the context.
123 imageBuffer->drawPattern(context, srcRect, patternTransform, phase, styleColorSpace, compositeOp, destRect);
124}
125
126void CrossfadeGeneratedImage::imageChanged(CachedImage* image, const IntRect* rect)
127{
128 UNUSED_PARAM(image);
129 m_observer->changedInRect(this, *rect);
130}
131
132}