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 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.
24 */
25
26#include "config.h"
27#include "CrossfadeGeneratedImage.h"
28
29#include "FloatRect.h"
30#include "GraphicsContext.h"
31#include "ImageBuffer.h"
32#include <wtf/text/TextStream.h>
33
34namespace WebCore {
35
36CrossfadeGeneratedImage::CrossfadeGeneratedImage(Image& fromImage, Image& toImage, float percentage, const FloatSize& crossfadeSize, const FloatSize& size)
37 : m_fromImage(fromImage)
38 , m_toImage(toImage)
39 , m_percentage(percentage)
40 , m_crossfadeSize(crossfadeSize)
41{
42 setContainerSize(size);
43}
44
45static void drawCrossfadeSubimage(GraphicsContext& context, Image& image, CompositeOperator operation, float opacity, const FloatSize& targetSize)
46{
47 FloatSize imageSize = image.size();
48
49 // SVGImage resets the opacity when painting, so we have to use transparency layers to accurately paint one at a given opacity.
50 bool useTransparencyLayer = image.isSVGImage();
51
52 GraphicsContextStateSaver stateSaver(context);
53
54 CompositeOperator drawImageOperation = operation;
55
56 if (useTransparencyLayer) {
57 context.setCompositeOperation(operation);
58 context.beginTransparencyLayer(opacity);
59 drawImageOperation = CompositeSourceOver;
60 } else
61 context.setAlpha(opacity);
62
63 if (targetSize != imageSize)
64 context.scale(targetSize / imageSize);
65
66 context.drawImage(image, IntPoint(), ImagePaintingOptions(drawImageOperation));
67
68 if (useTransparencyLayer)
69 context.endTransparencyLayer();
70}
71
72void CrossfadeGeneratedImage::drawCrossfade(GraphicsContext& context)
73{
74 // Draw nothing if either of the images hasn't loaded yet.
75 if (m_fromImage.ptr() == &Image::nullImage() || m_toImage.ptr() == &Image::nullImage())
76 return;
77
78 GraphicsContextStateSaver stateSaver(context);
79
80 context.clip(FloatRect(FloatPoint(), m_crossfadeSize));
81 context.beginTransparencyLayer(1);
82
83 drawCrossfadeSubimage(context, m_fromImage.get(), CompositeSourceOver, 1 - m_percentage, m_crossfadeSize);
84 drawCrossfadeSubimage(context, m_toImage.get(), CompositePlusLighter, m_percentage, m_crossfadeSize);
85
86 context.endTransparencyLayer();
87}
88
89ImageDrawResult CrossfadeGeneratedImage::draw(GraphicsContext& context, const FloatRect& dstRect, const FloatRect& srcRect, CompositeOperator compositeOp, BlendMode blendMode, DecodingMode, ImageOrientationDescription)
90{
91 GraphicsContextStateSaver stateSaver(context);
92 context.setCompositeOperation(compositeOp, blendMode);
93 context.clip(dstRect);
94 context.translate(dstRect.location());
95 if (dstRect.size() != srcRect.size())
96 context.scale(dstRect.size() / srcRect.size());
97 context.translate(-srcRect.location());
98
99 drawCrossfade(context);
100 return ImageDrawResult::DidDraw;
101}
102
103void CrossfadeGeneratedImage::drawPattern(GraphicsContext& context, const FloatRect& dstRect, const FloatRect& srcRect, const AffineTransform& patternTransform, const FloatPoint& phase, const FloatSize& spacing, CompositeOperator compositeOp, BlendMode blendMode)
104{
105 std::unique_ptr<ImageBuffer> imageBuffer = ImageBuffer::create(size(), context.renderingMode());
106 if (!imageBuffer)
107 return;
108
109 // Fill with the cross-faded image.
110 GraphicsContext& graphicsContext = imageBuffer->context();
111 drawCrossfade(graphicsContext);
112
113 // Tile the image buffer into the context.
114 imageBuffer->drawPattern(context, dstRect, srcRect, patternTransform, phase, spacing, compositeOp, blendMode);
115}
116
117void CrossfadeGeneratedImage::dump(TextStream& ts) const
118{
119 GeneratedImage::dump(ts);
120 ts.dumpProperty("from-image", m_fromImage.get());
121 ts.dumpProperty("to-image", m_toImage.get());
122 ts.dumpProperty("percentage", m_percentage);
123}
124
125}
126