Home | History | Annotate | Download | only in win
      1 /*
      2  * Copyright (C) 2008 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 "DragImage.h"
     28 
     29 #include "BitmapInfo.h"
     30 #include "CachedImage.h"
     31 #include "GraphicsContext.h"
     32 #include "Image.h"
     33 #include "RetainPtr.h"
     34 
     35 #include <cairo-win32.h>
     36 #include "GraphicsContextPlatformPrivateCairo.h"
     37 
     38 #include <windows.h>
     39 
     40 extern "C" {
     41 typedef struct _cairo* CairoContextRef;
     42 }
     43 
     44 namespace WebCore {
     45 
     46 void deallocContext(CairoContextRef target)
     47 {
     48     cairo_destroy(target);
     49 }
     50 
     51 HBITMAP allocImage(HDC dc, IntSize size, CairoContextRef* targetRef)
     52 {
     53     BitmapInfo bmpInfo = BitmapInfo::create(size);
     54 
     55     LPVOID bits;
     56     HBITMAP hbmp = CreateDIBSection(dc, &bmpInfo, DIB_RGB_COLORS, &bits, 0, 0);
     57 
     58     // At this point, we have a Cairo surface that points to a Windows DIB.  The DIB interprets
     59     // with the opposite meaning of positive Y axis, so everything we draw into this cairo
     60     // context is going to be upside down.
     61     if (!targetRef)
     62         return hbmp;
     63 
     64     cairo_surface_t* bitmapContext = cairo_image_surface_create_for_data((unsigned char*)bits,
     65                                                CAIRO_FORMAT_ARGB32,
     66                                                bmpInfo.bmiHeader.biWidth,
     67                                                bmpInfo.bmiHeader.biHeight,
     68                                                bmpInfo.bmiHeader.biWidth * 4);
     69 
     70     if (!bitmapContext) {
     71         DeleteObject(hbmp);
     72         return 0;
     73     }
     74 
     75     *targetRef = cairo_create (bitmapContext);
     76     cairo_surface_destroy (bitmapContext);
     77 
     78     // At this point, we have a Cairo surface that points to a Windows DIB.  The DIB interprets
     79     // with the opposite meaning of positive Y axis, so everything we draw into this cairo
     80     // context is going to be upside down.
     81     //
     82     // So, we must invert the CTM for the context so that drawing commands will be flipped
     83     // before they get written to the internal buffer.
     84     cairo_matrix_t matrix;
     85     cairo_matrix_init(&matrix, 1.0, 0.0, 0.0, -1.0, 0.0, size.height());
     86     cairo_set_matrix(*targetRef, &matrix);
     87 
     88     return hbmp;
     89 }
     90 
     91 static cairo_surface_t* createCairoContextFromBitmap(HBITMAP bitmap)
     92 {
     93     BITMAP info;
     94     GetObject(bitmap, sizeof(info), &info);
     95     ASSERT(info.bmBitsPixel == 32);
     96 
     97     // At this point, we have a Cairo surface that points to a Windows BITMAP.  The BITMAP
     98     // has the opposite meaning of positive Y axis, so everything we draw into this cairo
     99     // context is going to be upside down.
    100     return cairo_image_surface_create_for_data((unsigned char*)info.bmBits,
    101                                                CAIRO_FORMAT_ARGB32,
    102                                                info.bmWidth,
    103                                                info.bmHeight,
    104                                                info.bmWidthBytes);
    105 }
    106 
    107 DragImageRef scaleDragImage(DragImageRef image, FloatSize scale)
    108 {
    109     // FIXME: due to the way drag images are done on windows we need
    110     // to preprocess the alpha channel <rdar://problem/5015946>
    111     if (!image)
    112         return 0;
    113 
    114     IntSize srcSize = dragImageSize(image);
    115     IntSize dstSize(static_cast<int>(srcSize.width() * scale.width()), static_cast<int>(srcSize.height() * scale.height()));
    116 
    117     HBITMAP hbmp = 0;
    118     HDC dc = GetDC(0);
    119     HDC dstDC = CreateCompatibleDC(dc);
    120 
    121     if (!dstDC)
    122         goto exit;
    123 
    124     CairoContextRef targetContext;
    125     hbmp = allocImage(dstDC, dstSize, &targetContext);
    126     if (!hbmp)
    127         goto exit;
    128 
    129     cairo_surface_t* srcImage = createCairoContextFromBitmap(image);
    130 
    131     // Scale the target surface to the new image size, and flip it
    132     // so that when we set the srcImage as the surface it will draw
    133     // right-side-up.
    134     cairo_translate(targetContext, 0, dstSize.height());
    135     cairo_scale(targetContext, scale.width(), -scale.height());
    136     cairo_set_source_surface (targetContext, srcImage, 0.0, 0.0);
    137 
    138     // Now we can paint and get the correct result
    139     cairo_paint(targetContext);
    140 
    141     cairo_surface_destroy (srcImage);
    142     cairo_destroy(targetContext);
    143     ::DeleteObject(image);
    144     image = 0;
    145 
    146 exit:
    147     if (!hbmp)
    148         hbmp = image;
    149     if (dstDC)
    150         DeleteDC(dstDC);
    151     ReleaseDC(0, dc);
    152     return hbmp;
    153 }
    154 
    155 DragImageRef createDragImageFromImage(Image* img)
    156 {
    157     HBITMAP hbmp = 0;
    158     HDC dc = GetDC(0);
    159     HDC workingDC = CreateCompatibleDC(dc);
    160     if (!workingDC)
    161         goto exit;
    162 
    163     CairoContextRef drawContext = 0;
    164     hbmp = allocImage(workingDC, img->size(), &drawContext);
    165     if (!hbmp)
    166         goto exit;
    167 
    168     if (!drawContext) {
    169         ::DeleteObject(hbmp);
    170         hbmp = 0;
    171     }
    172 
    173     cairo_set_source_rgb (drawContext, 1.0, 0.0, 1.0);
    174     cairo_fill_preserve (drawContext);
    175 
    176     cairo_surface_t* srcImage = img->nativeImageForCurrentFrame();
    177 
    178     // Draw the image.
    179     cairo_set_source_surface(drawContext, srcImage, 0.0, 0.0);
    180     cairo_paint(drawContext);
    181 
    182     cairo_destroy (drawContext);
    183 
    184 exit:
    185     if (workingDC)
    186         DeleteDC(workingDC);
    187     ReleaseDC(0, dc);
    188     return hbmp;
    189 }
    190 
    191 }
    192