1/*
2 *  Copyright (C) 2007-2009 Torch Mobile, Inc. All rights reserved.
3 *  Copyright (C) 2010 Patrick Gansterer <paroga@paroga.com>
4 *
5 *  This library is free software; you can redistribute it and/or
6 *  modify it under the terms of the GNU Library General Public
7 *  License as published by the Free Software Foundation; either
8 *  version 2 of the License, or (at your option) any later version.
9 *
10 *  This library is distributed in the hope that it will be useful,
11 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 *  Library General Public License for more details.
14 *
15 *  You should have received a copy of the GNU Library General Public License
16 *  along with this library; see the file COPYING.LIB.  If not, write to
17 *  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 *  Boston, MA 02110-1301, USA.
19 */
20
21#include "config.h"
22#include "SharedBitmap.h"
23
24#include "GDIExtras.h"
25#include "GraphicsContext.h"
26#include "GraphicsTypes.h"
27#include "TransformationMatrix.h"
28#include "WinCEGraphicsExtras.h"
29#include <wtf/HashSet.h>
30#include <wtf/RefCountedLeakCounter.h>
31#include <wtf/PassOwnArrayPtr.h>
32#include <wtf/OwnPtr.h>
33
34#include <windows.h>
35
36namespace WebCore {
37
38#ifndef NDEBUG
39static WTF::RefCountedLeakCounter sharedBitmapLeakCounter("SharedBitmap");
40#endif
41
42
43PassRefPtr<SharedBitmap> SharedBitmap::create(const IntSize& size, BitmapInfo::BitCount bitCount, bool initPixels)
44{
45    RefPtr<SharedBitmap> resultantBitmap = adoptRef(new SharedBitmap(size, bitCount, initPixels));
46    if (resultantBitmap && !resultantBitmap->bytes())
47        return 0;
48    return resultantBitmap.release();
49}
50
51PassRefPtr<SharedBitmap> SharedBitmap::create(const Vector<unsigned>& data, const IntSize& size, bool hasAlpha)
52{
53    RefPtr<SharedBitmap> result = create(size, BitmapInfo::BitCount32, false);
54    if (!result)
55        return 0;
56    memcpy(result->bytes(), data.data(), data.size() * sizeof(unsigned));
57    result->setHasAlpha(hasAlpha);
58    return result.release();
59}
60
61SharedBitmap::SharedBitmap(const IntSize& size, BitmapInfo::BitCount bitCount, bool initPixels)
62    : m_bmpInfo(BitmapInfo::createBottomUp(size, bitCount))
63    , m_locked(false)
64    , m_usesTransparentColor(false)
65    , m_transparentColor(RGB(0, 0, 0))
66    , m_pixels(0)
67    , m_hasAlpha(false)
68    , m_validHeight(abs(size.height()))
69    , m_hbitmap(0)
70{
71#ifndef NDEBUG
72    sharedBitmapLeakCounter.increment();
73#endif
74
75    unsigned bufferSize = m_bmpInfo.numPixels();
76    if (bitCount == BitmapInfo::BitCount16)
77        bufferSize /= 2;
78
79    m_pixelData = adoptArrayPtr(new unsigned[bufferSize]);
80    m_pixels = m_pixelData.get();
81
82    if (initPixels)
83        resetPixels();
84}
85
86SharedBitmap::~SharedBitmap()
87{
88#ifndef NDEBUG
89    sharedBitmapLeakCounter.decrement();
90#endif
91}
92
93void SharedBitmap::resetPixels(bool black)
94{
95    if (!m_pixels)
96        return;
97
98    unsigned bufferSize = m_bmpInfo.numPixels();
99    if (black) {
100        unsigned bufferSizeInBytes = bufferSize * (is16bit() ? 2 : 4);
101        memset(m_pixels, 0, bufferSizeInBytes);
102        return;
103    }
104
105    if (is16bit()) {
106        // Fill it with white color
107        wmemset(static_cast<wchar_t*>(m_pixels), 0xFFFF, bufferSize);
108        return;
109    }
110
111    // Make it white but transparent
112    unsigned* pixel = static_cast<unsigned*>(m_pixels);
113    const unsigned* bufferEnd = pixel + bufferSize;
114    while (pixel < bufferEnd)
115        *pixel++ = 0x00FFFFFF;
116}
117
118static inline unsigned short convert32To16(unsigned pixel)
119{
120    unsigned short r = static_cast<unsigned short>((pixel & 0x00F80000) >> 8);
121    unsigned short g = static_cast<unsigned short>((pixel & 0x0000FC00) >> 5);
122    unsigned short b = static_cast<unsigned short>((pixel & 0x000000F8) >> 3);
123    return r | g | b;
124}
125
126bool SharedBitmap::to16bit()
127{
128    if (m_locked)
129        return false;
130    if (is16bit())
131        return true;
132
133    BitmapInfo newBmpInfo = BitmapInfo::create(m_bmpInfo.size(), BitmapInfo::BitCount16);
134
135    int width = newBmpInfo.width();
136    int paddedWidth = newBmpInfo.paddedWidth();
137    int bufferSize = paddedWidth * newBmpInfo.height();
138    OwnArrayPtr<unsigned> newPixelData = adoptArrayPtr(new unsigned[bufferSize / 2]);
139    void* newPixels = newPixelData.get();
140
141    if (!newPixels)
142        return false;
143
144    unsigned short* p16 = static_cast<unsigned short*>(newPixels);
145    const unsigned* p32 = static_cast<const unsigned*>(m_pixels);
146
147    bool skips = paddedWidth != width;
148
149    const unsigned short* p16end = p16 + bufferSize;
150    while (p16 < p16end) {
151        for (unsigned short* p16lineEnd = p16 + width; p16 < p16lineEnd; )
152            *p16++ = convert32To16(*p32++);
153
154        if (skips)
155            *p16++ = 0;
156    }
157
158    if (m_hbitmap)
159        m_hbitmap = nullptr;
160    else
161        m_pixelData = newPixelData.release();
162
163    m_pixels = newPixels;
164    m_bmpInfo = newBmpInfo;
165
166    setHasAlpha(false);
167    return true;
168}
169
170bool SharedBitmap::freeMemory()
171{
172    if (m_locked)
173        return false;
174
175    if (m_hbitmap) {
176        m_hbitmap = nullptr;
177        m_pixels = 0;
178        return true;
179    }
180
181    if (m_pixels) {
182        m_pixelData = nullptr;
183        m_pixels = 0;
184        return true;
185    }
186
187    return false;
188}
189
190PassOwnPtr<HBITMAP> SharedBitmap::createHandle(void** pixels, BitmapInfo* bmpInfo, int height, bool use16bit) const
191{
192    if (!m_pixels)
193        return 0;
194
195    if (height == -1)
196        height = this->height();
197    *bmpInfo = BitmapInfo::createBottomUp(IntSize(width(), height), (use16bit || is16bit()) ? BitmapInfo::BitCount16 : BitmapInfo::BitCount32);
198
199    OwnPtr<HBITMAP> hbmp = adoptPtr(CreateDIBSection(0, bmpInfo, DIB_RGB_COLORS, pixels, 0, 0));
200
201    if (!hbmp)
202        return 0;
203
204    OwnPtr<HDC> bmpDC = adoptPtr(CreateCompatibleDC(0));
205    HGDIOBJ hOldBmp = SelectObject(bmpDC.get(), hbmp.get());
206
207    StretchDIBits(bmpDC.get(), 0, 0, width(), height, 0, 0, width(), height, m_pixels, &m_bmpInfo, DIB_RGB_COLORS, SRCCOPY);
208
209    SelectObject(bmpDC.get(), hOldBmp);
210
211    return hbmp.release();
212}
213
214bool SharedBitmap::ensureHandle()
215{
216    if (m_hbitmap)
217        return true;
218
219    if (!m_pixels)
220        return false;
221
222    if (m_locked)
223        return false;
224
225    BitmapInfo bmpInfo;
226    void* pixels;
227    m_hbitmap = createHandle(&pixels, &bmpInfo, -1, !hasAlpha());
228
229    if (!m_hbitmap)
230        return false;
231
232    m_pixelData = nullptr;
233    m_pixels = pixels;
234    m_bmpInfo = bmpInfo;
235
236    return true;
237}
238
239void SharedBitmap::draw(GraphicsContext* ctxt, const IntRect& dstRect, const IntRect& srcRect, ColorSpace styleColorSpace, CompositeOperator compositeOp)
240{
241    if (!m_pixels)
242        return;
243    ctxt->drawBitmap(this, dstRect, srcRect, styleColorSpace, compositeOp);
244}
245
246void SharedBitmap::draw(HDC hdc, const IntRect& dstRect, const IntRect& srcRect, CompositeOperator compositeOp)
247{
248    if (!m_pixels)
249        return;
250
251    if (dstRect.isEmpty() || srcRect.isEmpty())
252        return;
253
254    HBITMAP hbitmap = 0;
255    OwnPtr<HBITMAP> hTempBitmap;
256    bool usingHandle = compositeOp == CompositeSourceOver && (hasAlpha() && hasAlphaBlendSupport() || usesTransparentColor());
257
258    if (usingHandle) {
259        if (ensureHandle())
260            hbitmap = m_hbitmap.get();
261        else {
262            void* pixels;
263            BitmapInfo bmpInfo;
264            hTempBitmap = createHandle(&pixels, &bmpInfo, -1, usesTransparentColor());
265            hbitmap = hTempBitmap.get();
266        }
267    }
268    if (!hbitmap) {
269        // FIXME: handle other composite operation types?
270        DWORD rop = compositeOp == CompositeCopy ? SRCCOPY
271            : compositeOp == CompositeXOR ? PATINVERT
272            : compositeOp == CompositeClear ? WHITENESS
273            : SRCCOPY;
274
275        StretchDIBits(hdc, dstRect.x(), dstRect.y(), dstRect.width(), dstRect.height(),
276            srcRect.x(), srcRect.y(), srcRect.width(), srcRect.height(), m_pixels, &m_bmpInfo, DIB_RGB_COLORS, rop);
277        return;
278    }
279
280    OwnPtr<HDC> hmemdc = adoptPtr(CreateCompatibleDC(hdc));
281    HGDIOBJ hOldBmp = SelectObject(hmemdc.get(), hbitmap);
282
283    if (!usesTransparentColor() && hasAlphaBlendSupport()) {
284        static const BLENDFUNCTION blend = { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA };
285        bool success = alphaBlendIfSupported(hdc, dstRect.x(), dstRect.y(), dstRect.width(), dstRect.height(), hmemdc.get(),
286            srcRect.x(), srcRect.y(), srcRect.width(), srcRect.height(), blend);
287        ASSERT_UNUSED(success, success);
288    } else {
289        TransparentBlt(hdc, dstRect.x(), dstRect.y(), dstRect.width(), dstRect.height(), hmemdc.get(),
290            srcRect.x(), srcRect.y(), srcRect.width(), srcRect.height(), transparentColor());
291    }
292
293    SelectObject(hmemdc.get(), hOldBmp);
294}
295
296PassOwnPtr<HBITMAP> SharedBitmap::clipBitmap(const IntRect& rect, bool useAlpha, BitmapInfo& bmpInfo, void*& pixels)
297{
298    if (!bytes())
299        return 0;
300
301    int oldWidth = width();
302    int oldHeight = height();
303    int copyWidth = std::min<int>(rect.width(), oldWidth - rect.x());
304    int copyHeight = std::min<int>(rect.height(), oldHeight - rect.y());
305    if (!copyWidth || !copyHeight)
306        return 0;
307
308    bmpInfo = BitmapInfo::createBottomUp(IntSize(copyWidth, copyHeight), (useAlpha && is32bit()) ? BitmapInfo::BitCount32 : BitmapInfo::BitCount16);
309    OwnPtr<HBITMAP> newBmp = adoptPtr(CreateDIBSection(0, &bmpInfo, DIB_RGB_COLORS, &pixels, 0, 0));
310
311    if (!newBmp)
312        return 0;
313
314    OwnPtr<HDC> dcNew = adoptPtr(CreateCompatibleDC(0));
315    HGDIOBJ tmpNew = SelectObject(dcNew.get(), newBmp.get());
316
317    StretchDIBits(dcNew.get(), 0, 0, copyWidth, copyHeight, rect.x(), rect.y(), copyWidth, copyHeight,
318        bytes(), &bitmapInfo(), DIB_RGB_COLORS, SRCCOPY);
319
320    SelectObject(dcNew.get(), tmpNew);
321    return newBmp.release();
322}
323
324PassRefPtr<SharedBitmap> SharedBitmap::clipBitmap(const IntRect& rect, bool useAlpha)
325{
326    int oldWidth = width();
327    int oldHeight = height();
328    int copyWidth = std::min<int>(rect.width(), oldWidth - rect.x());
329    int copyHeight = std::min<int>(rect.height(), oldHeight - rect.y());
330    if (!copyWidth || !copyHeight)
331        return 0;
332
333    RefPtr<SharedBitmap> newBmp = create(IntSize(copyWidth, copyHeight), useAlpha && is32bit() ? BitmapInfo::BitCount32 : BitmapInfo::BitCount16, false);
334
335    if (!newBmp || !newBmp->bytes())
336        return 0;
337
338    DCHolder dcNew(newBmp.get());
339
340    StretchDIBits(dcNew.get(), 0, 0, copyWidth, copyHeight, rect.x(), rect.y(), copyWidth, copyHeight,
341        bytes(), &bitmapInfo(), DIB_RGB_COLORS, SRCCOPY);
342
343    return newBmp;
344}
345
346static void drawPatternSimple(HDC hdc, const RECT& destRect, HBITMAP hbmp, const POINT& phase)
347{
348    OwnPtr<HBRUSH> hBrush = adoptPtr(CreatePatternBrush(hbmp));
349    if (!hBrush)
350        return;
351
352    POINT oldOrg;
353    SetBrushOrgEx(hdc, destRect.left - phase.x, destRect.top - phase.y, &oldOrg);
354    FillRect(hdc, &destRect, hBrush.get());
355    SetBrushOrgEx(hdc, oldOrg.x, oldOrg.y, 0);
356}
357
358static void drawPatternSimple(HDC hdc, const RECT& destRect, const SharedBitmap* bmp, const SIZE& bmpSize, const POINT& phase)
359{
360    int dstY = destRect.top;
361    for (int sourceY = phase.y; dstY < destRect.bottom; ) {
362        int sourceH = std::min<int>(bmpSize.cy - sourceY, destRect.bottom - dstY);
363        int dstX = destRect.left;
364        for (int sourceX = phase.x; dstX < destRect.right; ) {
365            int sourceW = std::min<int>(bmpSize.cx - sourceX, destRect.right - dstX);
366
367            StretchDIBits(hdc, dstX, dstY, sourceW, sourceH, sourceX, sourceY, sourceW, sourceH,
368                bmp->bytes(), &bmp->bitmapInfo(), DIB_RGB_COLORS, SRCCOPY);
369
370            dstX += sourceW;
371            sourceX = 0;
372        }
373
374        dstY += sourceH;
375        sourceY = 0;
376    }
377}
378
379static LONG normalizePhase(LONG phase, int limit)
380{
381    if (!phase || limit < 2)
382        return 0;
383
384    if (limit == 2)
385        return phase & 1;
386
387    if (phase < 0) {
388        phase = -phase;
389        if (phase > limit)
390            phase = static_cast<LONG>(static_cast<unsigned>(phase) % static_cast<unsigned>(limit));
391        if (phase)
392            phase = limit - phase;
393        return phase;
394    }
395
396    if (phase < limit)
397        return phase;
398
399    return static_cast<LONG>(static_cast<unsigned>(phase) % static_cast<unsigned>(limit));
400}
401
402void SharedBitmap::drawPattern(GraphicsContext* ctxt, const FloatRect& tileRectIn, const AffineTransform& patternTransform,
403                        const FloatPoint& phase, ColorSpace styleColorSpace, CompositeOperator op, const FloatRect& destRect, const IntSize& origSourceSize)
404{
405    if (!m_pixels)
406        return;
407    ctxt->drawBitmapPattern(this, tileRectIn, patternTransform, phase, styleColorSpace, op, destRect, origSourceSize);
408}
409
410void SharedBitmap::drawPattern(HDC hdc, const AffineTransform& transform, const FloatRect& tileRectIn, const AffineTransform& patternTransform,
411                        const FloatPoint& phase, ColorSpace styleColorSpace, CompositeOperator op, const FloatRect& destRect, const IntSize& origSourceSize)
412{
413    if (!m_pixels)
414        return;
415
416    if (tileRectIn.width() <= 0 || tileRectIn.height() <= 0)
417        return;
418
419    bool useAlpha = op == CompositeSourceOver && hasAlpha() && is32bit();
420
421    int bmpWidth = width();
422    int bmpHeight = height();
423
424    FloatRect tileRect(tileRectIn);
425    if (bmpWidth != origSourceSize.width()) {
426        double rate = static_cast<double>(bmpWidth) / origSourceSize.width();
427        double temp = tileRect.width() * rate;
428        tileRect.setX(tileRect.x() * rate);
429        tileRect.setWidth(temp);
430        temp = tileRect.height() * rate;
431        tileRect.setY(tileRect.y() * rate);
432        tileRect.setHeight(temp);
433    }
434
435    OwnPtr<HBITMAP> clippedBmp;
436
437    if (tileRect.x() || tileRect.y() || tileRect.width() != bmpWidth || tileRect.height() != bmpHeight) {
438        BitmapInfo patternBmpInfo;
439        void* patternPixels;
440        clippedBmp = clipBitmap(IntRect(tileRect), useAlpha, patternBmpInfo, patternPixels);
441        if (!clippedBmp)
442            return;
443
444        bmpWidth = tileRect.width();
445        bmpHeight = tileRect.height();
446    }
447
448    AffineTransform tf = patternTransform * transform;
449
450    FloatRect trRect = tf.mapRect(destRect);
451
452    RECT clipBox;
453    int clipType = GetClipBox(hdc, &clipBox);
454    if (clipType == SIMPLEREGION)
455        trRect.intersect(FloatRect(clipBox.left, clipBox.top, clipBox.right - clipBox.left, clipBox.bottom - clipBox.top));
456    else if (clipType == COMPLEXREGION) {
457        OwnPtr<HRGN> clipRgn = adoptPtr(CreateRectRgn(0, 0, 0, 0));
458        if (GetClipRgn(hdc, clipRgn.get()) > 0) {
459            DWORD regionDataSize = GetRegionData(clipRgn.get(), sizeof(RGNDATA), 0);
460            if (regionDataSize) {
461                Vector<RGNDATA> regionData(regionDataSize);
462                GetRegionData(clipRgn.get(), regionDataSize, regionData.data());
463                RECT* rect = reinterpret_cast<RECT*>(regionData[0].Buffer);
464                for (DWORD i = 0; i < regionData[0].rdh.nCount; ++i, ++rect)
465                    trRect.intersect(FloatRect(rect->left, rect->top, rect->right - rect->left, rect->bottom - rect->top));
466            }
467        }
468    }
469
470    if (trRect.width() <= 0 || trRect.height() <= 0)
471        return;
472
473    trRect.inflate(1);
474    IntRect visibleDstRect = enclosingIntRect(tf.inverse().mapRect(trRect));
475    visibleDstRect.intersect(IntRect(destRect));
476
477    if (visibleDstRect.width() <= 0 || visibleDstRect.height() <= 0)
478        return;
479
480    trRect = tf.mapRect(visibleDstRect);
481    RECT dstRectWin = {
482        stableRound(trRect.x()),
483        stableRound(trRect.y()),
484        stableRound(trRect.maxX()),
485        stableRound(trRect.maxY()),
486    };
487    if (dstRectWin.right <= dstRectWin.left || dstRectWin.bottom <= dstRectWin.top)
488        return;
489
490    SIZE bmpSize = { bmpWidth, bmpHeight };
491
492    // Relative to destination, in bitmap pixels
493    POINT phaseWin = { stableRound(visibleDstRect.x() - phase.x()), stableRound(visibleDstRect.y() - phase.y()) };
494    phaseWin.x = normalizePhase(phaseWin.x, bmpSize.cx);
495    phaseWin.y = normalizePhase(phaseWin.y, bmpSize.cy);
496
497    RECT srcRectWin = {
498        0,
499        0,
500        stableRound(visibleDstRect.maxX()) - stableRound(visibleDstRect.x()),
501        stableRound(visibleDstRect.maxY()) - stableRound(visibleDstRect.y())
502    };
503    if (srcRectWin.right <= 0 || srcRectWin.bottom <= 0)
504        return;
505
506    BitmapInfo bmpInfo = BitmapInfo::createBottomUp(IntSize(srcRectWin.right, srcRectWin.bottom), useAlpha ? BitmapInfo::BitCount32 : BitmapInfo::BitCount16);
507    void* pixels;
508    OwnPtr<HBITMAP> hbmpTemp = adoptPtr(CreateDIBSection(0, &bmpInfo, DIB_RGB_COLORS, &pixels, 0, 0));
509
510    if (!hbmpTemp)
511        return;
512
513    OwnPtr<HDC> hmemdc = adoptPtr(CreateCompatibleDC(hdc));
514    HGDIOBJ oldBmp = SelectObject(hmemdc.get(), hbmpTemp.get());
515    if (clippedBmp)
516        drawPatternSimple(hmemdc.get(), srcRectWin, clippedBmp.get(), phaseWin);
517    else if ((op != CompositeSourceOver || canUseDIBits()) && srcRectWin.right <= bmpSize.cx * 2 && srcRectWin.bottom <= bmpSize.cy * 2)
518        drawPatternSimple(hmemdc.get(), srcRectWin, this, bmpSize, phaseWin);
519    else if (ensureHandle())
520        drawPatternSimple(hmemdc.get(), srcRectWin, getHandle(), phaseWin);
521    else {
522        void* pixels;
523        BitmapInfo bmpInfo;
524        OwnPtr<HBITMAP> hbmp = createHandle(&pixels, &bmpInfo, -1, false);
525        if (hbmp)
526            drawPatternSimple(hmemdc.get(), srcRectWin, hbmp.get(), phaseWin);
527        else {
528            SelectObject(hmemdc.get(), oldBmp);
529            return;
530        }
531    }
532
533    if (useAlpha && hasAlphaBlendSupport()) {
534        static const BLENDFUNCTION blend = { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA };
535        bool success = alphaBlendIfSupported(hdc, dstRectWin.left, dstRectWin.top, dstRectWin.right - dstRectWin.left, dstRectWin.bottom - dstRectWin.top,
536            hmemdc.get(), 0, 0, srcRectWin.right, srcRectWin.bottom, blend);
537        ASSERT_UNUSED(success, success);
538    } else if (useAlpha && !hasAlphaBlendSupport() || op == CompositeSourceOver && usesTransparentColor()) {
539        TransparentBlt(hdc, dstRectWin.left, dstRectWin.top, dstRectWin.right - dstRectWin.left,
540            dstRectWin.bottom - dstRectWin.top, hmemdc.get(), 0, 0, srcRectWin.right, srcRectWin.bottom, transparentColor());
541    } else {
542        DWORD bmpOp = op == CompositeCopy ? SRCCOPY
543                    : op == CompositeSourceOver ? SRCCOPY
544                    : op == CompositeXOR ? PATINVERT
545                    : op == CompositeClear ? WHITENESS
546                    : SRCCOPY; // FIXEME: other types?
547
548        StretchDIBits(hdc, dstRectWin.left, dstRectWin.top, dstRectWin.right - dstRectWin.left,
549            dstRectWin.bottom - dstRectWin.top, 0, 0, srcRectWin.right, srcRectWin.bottom,
550            pixels, &bmpInfo, DIB_RGB_COLORS, bmpOp);
551    }
552    SelectObject(hmemdc.get(), oldBmp);
553}
554
555SharedBitmap::DCProvider* SharedBitmap::s_dcProvider = new SharedBitmap::DCProvider;
556
557HDC SharedBitmap::DCProvider::getDC(SharedBitmap* bmp, unsigned* key)
558{
559    if (!bmp || !bmp->ensureHandle())
560        return 0;
561
562    HDC hdc = CreateCompatibleDC(0);
563    if (!hdc)
564        return 0;
565
566    *key = reinterpret_cast<unsigned>(SelectObject(hdc, bmp->getHandle()));
567    RECT rect = { 0, 0, bmp->width(), bmp->height() };
568    OwnPtr<HRGN> clipRgn = adoptPtr(CreateRectRgnIndirect(&rect));
569    SelectClipRgn(hdc, clipRgn.get());
570
571    return hdc;
572}
573
574void SharedBitmap::DCProvider::releaseDC(SharedBitmap*, HDC hdc, unsigned key1)
575{
576    if (!hdc)
577        return;
578
579    SelectObject(hdc, reinterpret_cast<HGDIOBJ>(key1));
580    DeleteDC(hdc);
581}
582
583void SharedBitmap::clearPixels(const IntRect& rect)
584{
585    if (!m_pixels)
586        return;
587
588    IntRect bmpRect(0, 0, width(), height());
589    bmpRect.intersect(rect);
590    if (is16bit()) {
591        unsigned w = m_bmpInfo.paddedWidth();
592        unsigned short* dst = static_cast<unsigned short*>(m_pixels);
593        dst += bmpRect.y() * w + bmpRect.x();
594        int wordsToSet = bmpRect.width();
595        const unsigned short* dstEnd = dst + bmpRect.height() * w;
596        while (dst < dstEnd) {
597            wmemset(reinterpret_cast<wchar_t*>(dst), 0, wordsToSet);
598            dst += w;
599        }
600        return;
601    }
602
603    unsigned w = width();
604    unsigned* dst = static_cast<unsigned*>(m_pixels);
605    dst += bmpRect.y() * w + bmpRect.x();
606    int wordsToSet = bmpRect.width() * 2;
607    const unsigned* dstEnd = dst + bmpRect.height() * w;
608    while (dst < dstEnd) {
609        wmemset(reinterpret_cast<wchar_t*>(dst), 0, wordsToSet);
610        dst += w;
611    }
612}
613
614} // namespace WebCore
615