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