1/*
2 * Copyright (C) 2007 Apple Computer, Kevin Ollivier.  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 "Image.h"
28
29#include "AffineTransform.h"
30#include "BitmapImage.h"
31#include "FloatConversion.h"
32#include "FloatRect.h"
33#include "GraphicsContext.h"
34#include "ImageObserver.h"
35#include "NotImplemented.h"
36#include "SharedBuffer.h"
37
38#include <math.h>
39#include <stdio.h>
40
41#include <wx/defs.h>
42#include <wx/bitmap.h>
43#include <wx/dc.h>
44#include <wx/dcmemory.h>
45#include <wx/dcgraph.h>
46#include <wx/graphics.h>
47#include <wx/image.h>
48#include <wx/thread.h>
49
50namespace WebCore {
51
52// this is in GraphicsContextWx.cpp
53int getWxCompositingOperation(CompositeOperator op, bool hasAlpha);
54
55bool FrameData::clear(bool clearMetadata)
56{
57    if (clearMetadata)
58        m_haveMetadata = false;
59
60    if (m_frame) {
61        delete m_frame;
62        m_frame = 0;
63        return true;
64    }
65    return false;
66}
67
68// ================================================
69// Image Class
70// ================================================
71
72PassRefPtr<Image> Image::loadPlatformResource(const char *name)
73{
74    // FIXME: We need to have some 'placeholder' graphics for things like missing
75    // plugins or broken images.
76    Vector<char> arr;
77    RefPtr<Image> img = BitmapImage::create();
78    RefPtr<SharedBuffer> buffer = SharedBuffer::create(arr.data(), arr.size());
79    img->setData(buffer, true);
80    return img.release();
81}
82
83void BitmapImage::initPlatformData()
84{
85    // FIXME: NYI
86}
87
88// Drawing Routines
89
90void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dst, const FloatRect& src, ColorSpace styleColorSpace, CompositeOperator op)
91{
92    if (!m_source.initialized())
93        return;
94
95    if (mayFillWithSolidColor()) {
96        fillWithSolidColor(ctxt, dst, solidColor(), styleColorSpace, op);
97        return;
98    }
99
100#if USE(WXGC)
101    wxGCDC* context = (wxGCDC*)ctxt->platformContext();
102    wxGraphicsContext* gc = context->GetGraphicsContext();
103    wxGraphicsBitmap* bitmap = frameAtIndex(m_currentFrame);
104#else
105    wxWindowDC* context = ctxt->platformContext();
106    wxBitmap* bitmap = frameAtIndex(m_currentFrame);
107#endif
108
109    startAnimation();
110    if (!bitmap) // If it's too early we won't have an image yet.
111        return;
112
113    // If we're drawing a sub portion of the image or scaling then create
114    // a pattern transformation on the image and draw the transformed pattern.
115    // Test using example site at http://www.meyerweb.com/eric/css/edge/complexspiral/demo.html
116    // FIXME: NYI
117
118    ctxt->save();
119
120    // Set the compositing operation.
121    ctxt->setCompositeOperation(op);
122
123#if USE(WXGC)
124    float scaleX = src.width() / dst.width();
125    float scaleY = src.height() / dst.height();
126
127    FloatRect adjustedDestRect = dst;
128    FloatSize selfSize = currentFrameSize();
129
130    if (src.size() != selfSize) {
131        adjustedDestRect.setLocation(FloatPoint(dst.x() - src.x() / scaleX, dst.y() - src.y() / scaleY));
132        adjustedDestRect.setSize(FloatSize(selfSize.width() / scaleX, selfSize.height() / scaleY));
133    }
134
135    gc->Clip(dst.x(), dst.y(), dst.width(), dst.height());
136#if wxCHECK_VERSION(2,9,0)
137    gc->DrawBitmap(*bitmap, adjustedDestRect.x(), adjustedDestRect.y(), adjustedDestRect.width(), adjustedDestRect.height());
138#else
139    gc->DrawGraphicsBitmap(*bitmap, adjustedDestRect.x(), adjustedDestRect.y(), adjustedDestRect.width(), adjustedDestRect.height());
140#endif
141
142#else // USE(WXGC)
143    IntRect srcIntRect(src);
144    IntRect dstIntRect(dst);
145    bool rescaling = false;
146    if ((dstIntRect.width() != srcIntRect.width()) || (dstIntRect.height() != srcIntRect.height()))
147    {
148        rescaling = true;
149        wxImage img = bitmap->ConvertToImage();
150        img.Rescale(dstIntRect.width(), dstIntRect.height());
151        bitmap = new wxBitmap(img);
152    }
153
154    wxMemoryDC mydc;
155    ASSERT(bitmap->GetRefData());
156    mydc.SelectObject(*bitmap);
157
158    context->Blit((wxCoord)dstIntRect.x(),(wxCoord)dstIntRect.y(), (wxCoord)dstIntRect.width(), (wxCoord)dstIntRect.height(), &mydc,
159                    (wxCoord)srcIntRect.x(), (wxCoord)srcIntRect.y(), wxCOPY, true);
160    mydc.SelectObject(wxNullBitmap);
161
162    // NB: delete is causing crashes during page load, but not during the deletion
163    // itself. It occurs later on when a valid bitmap created in frameAtIndex
164    // suddenly becomes invalid after returning. It's possible these errors deal
165    // with reentrancy and threding problems.
166    //delete bitmap;
167    if (rescaling)
168    {
169        delete bitmap;
170        bitmap = NULL;
171    }
172#endif
173
174    ctxt->restore();
175
176    if (ImageObserver* observer = imageObserver())
177        observer->didDraw(this);
178}
179
180void Image::drawPattern(GraphicsContext* ctxt, const FloatRect& srcRect, const AffineTransform& patternTransform, const FloatPoint& phase, ColorSpace, CompositeOperator, const FloatRect& dstRect)
181{
182
183
184#if USE(WXGC)
185    wxGCDC* context = (wxGCDC*)ctxt->platformContext();
186    wxGraphicsBitmap* bitmap = nativeImageForCurrentFrame();
187#else
188    wxWindowDC* context = ctxt->platformContext();
189    wxBitmap* bitmap = nativeImageForCurrentFrame();
190#endif
191
192    if (!bitmap) // If it's too early we won't have an image yet.
193        return;
194
195    ctxt->save();
196    ctxt->clip(IntRect(dstRect.x(), dstRect.y(), dstRect.width(), dstRect.height()));
197
198    float currentW = 0;
199    float currentH = 0;
200
201#if USE(WXGC)
202    wxGraphicsContext* gc = context->GetGraphicsContext();
203
204    float adjustedX = phase.x() + srcRect.x() *
205                      narrowPrecisionToFloat(patternTransform.a());
206    float adjustedY = phase.y() + srcRect.y() *
207                      narrowPrecisionToFloat(patternTransform.d());
208
209    gc->ConcatTransform(patternTransform);
210#else
211    wxMemoryDC mydc;
212    mydc.SelectObject(*bitmap);
213#endif
214
215    wxPoint origin(context->GetDeviceOrigin());
216    wxSize clientSize(context->GetSize());
217
218    while ( currentW < dstRect.width()  && currentW < clientSize.x - origin.x ) {
219        while ( currentH < dstRect.height() && currentH < clientSize.y - origin.y) {
220#if USE(WXGC)
221#if wxCHECK_VERSION(2,9,0)
222            gc->DrawBitmap(*bitmap, adjustedX + currentW, adjustedY + currentH, (wxDouble)srcRect.width(), (wxDouble)srcRect.height());
223#else
224            gc->DrawGraphicsBitmap(*bitmap, adjustedX + currentW, adjustedY + currentH, (wxDouble)srcRect.width(), (wxDouble)srcRect.height());
225#endif
226#else
227            context->Blit((wxCoord)dstRect.x() + currentW, (wxCoord)dstRect.y() + currentH,
228                            (wxCoord)srcRect.width(), (wxCoord)srcRect.height(), &mydc,
229                            (wxCoord)srcRect.x(), (wxCoord)srcRect.y(), wxCOPY, true);
230#endif
231            currentH += srcRect.height();
232        }
233        currentW += srcRect.width();
234        currentH = 0;
235    }
236    ctxt->restore();
237
238#if !USE(WXGC)
239    mydc.SelectObject(wxNullBitmap);
240#endif
241
242    // NB: delete is causing crashes during page load, but not during the deletion
243    // itself. It occurs later on when a valid bitmap created in frameAtIndex
244    // suddenly becomes invalid after returning. It's possible these errors deal
245    // with reentrancy and threding problems.
246    //delete bitmap;
247
248    startAnimation();
249
250    if (ImageObserver* observer = imageObserver())
251        observer->didDraw(this);
252}
253
254void BitmapImage::checkForSolidColor()
255{
256    m_checkedForSolidColor = true;
257}
258
259void BitmapImage::invalidatePlatformData()
260{
261
262}
263
264}
265