Subversion Repositories Scribus

Rev

Rev 17188 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
16124 jghali 1
/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
2
/* Cairo - a vector graphics library with display and print output
3
 *
4
 * Copyright © 2005 Red Hat, Inc.
5
 *
6
 * This library is free software; you can redistribute it and/or
7
 * modify it either under the terms of the GNU Lesser General Public
8
 * License version 2.1 as published by the Free Software Foundation
9
 * (the "LGPL") or, at your option, under the terms of the Mozilla
10
 * Public License Version 1.1 (the "MPL"). If you do not alter this
11
 * notice, a recipient may use your version of this file under either
12
 * the MPL or the LGPL.
13
 *
14
 * You should have received a copy of the LGPL along with this library
15
 * in the file COPYING-LGPL-2.1; if not, write to the Free Software
18122 mrdocs 16
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16124 jghali 17
 * You should have received a copy of the MPL along with this library
18
 * in the file COPYING-MPL-1.1
19
 *
20
 * The contents of this file are subject to the Mozilla Public License
21
 * Version 1.1 (the "License"); you may not use this file except in
22
 * compliance with the License. You may obtain a copy of the License at
23
 * http://www.mozilla.org/MPL/
24
 *
25
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
26
 * OF ANY KIND, either express or implied. See the LGPL or the MPL for
27
 * the specific language governing rights and limitations.
28
 *
29
 * The Original Code is the cairo graphics library.
30
 *
31
 * The Initial Developer of the Original Code is Red Hat, Inc.
32
 *
33
 * Contributor(s):
34
 *      Owen Taylor <otaylor@redhat.com>
35
 *      Stuart Parmenter <stuart@mozilla.com>
36
 *      Vladimir Vukicevic <vladimir@pobox.com>
37
 */
38
 
39
#define WIN32_LEAN_AND_MEAN
40
/* We require Windows 2000 features such as ETO_PDY */
41
#if !defined(WINVER) || (WINVER < 0x0500)
42
# define WINVER 0x0500
43
#endif
44
#if !defined(_WIN32_WINNT) || (_WIN32_WINNT < 0x0500)
45
# define _WIN32_WINNT 0x0500
46
#endif
47
 
48
#include "cairoint.h"
49
 
50
#include "cairo-clip-private.h"
51
#include "cairo-paginated-private.h"
52
#include "cairo-win32-private.h"
53
#include "cairo-scaled-font-subsets-private.h"
54
#include "cairo-surface-fallback-private.h"
55
 
56
#include <wchar.h>
57
#include <windows.h>
58
 
59
#if defined(__MINGW32__) && !defined(ETO_PDY)
60
# define ETO_PDY 0x2000
61
#endif
62
 
63
#undef DEBUG_COMPOSITE
64
 
65
/* for older SDKs */
66
#ifndef SHADEBLENDCAPS
67
#define SHADEBLENDCAPS  120
68
#endif
69
#ifndef SB_NONE
70
#define SB_NONE         0x00000000
71
#endif
72
 
73
#define PELS_72DPI  ((LONG)(72. / 0.0254))
74
 
75
static const cairo_surface_backend_t cairo_win32_surface_backend;
76
 
77
/**
78
 * _cairo_win32_print_gdi_error:
79
 * @context: context string to display along with the error
80
 *
81
 * Helper function to dump out a human readable form of the
82
 * current error code.
83
 *
84
 * Return value: A cairo status code for the error code
85
 **/
86
cairo_status_t
87
_cairo_win32_print_gdi_error (const char *context)
88
{
89
    void *lpMsgBuf;
90
    DWORD last_error = GetLastError ();
91
 
92
    if (!FormatMessageW (FORMAT_MESSAGE_ALLOCATE_BUFFER |
93
                         FORMAT_MESSAGE_FROM_SYSTEM,
94
                         NULL,
95
                         last_error,
96
                         MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),
17188 jghali 97
                         (LPWSTR) &lpMsgBuf,
16124 jghali 98
                         0, NULL)) {
99
        fprintf (stderr, "%s: Unknown GDI error", context);
100
    } else {
17188 jghali 101
        fprintf (stderr, "%s: %S", context, (wchar_t *)lpMsgBuf);
16124 jghali 102
 
103
        LocalFree (lpMsgBuf);
104
    }
105
 
17188 jghali 106
        fflush (stderr);
107
 
16124 jghali 108
    /* We should switch off of last_status, but we'd either return
109
     * CAIRO_STATUS_NO_MEMORY or CAIRO_STATUS_UNKNOWN_ERROR and there
110
     * is no CAIRO_STATUS_UNKNOWN_ERROR.
111
     */
112
 
113
    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
114
}
115
 
116
uint32_t
117
_cairo_win32_flags_for_dc (HDC dc)
118
{
119
    uint32_t flags = 0;
120
 
121
    if (GetDeviceCaps(dc, TECHNOLOGY) == DT_RASDISPLAY) {
122
        flags |= CAIRO_WIN32_SURFACE_IS_DISPLAY;
123
 
124
        /* These will always be possible, but the actual GetDeviceCaps
125
         * calls will return whether they're accelerated or not.
126
         * We may want to use our own (pixman) routines sometimes
127
         * if they're eventually faster, but for now have GDI do
128
         * everything.
129
         */
130
        flags |= CAIRO_WIN32_SURFACE_CAN_BITBLT;
131
        flags |= CAIRO_WIN32_SURFACE_CAN_ALPHABLEND;
132
        flags |= CAIRO_WIN32_SURFACE_CAN_STRETCHBLT;
133
        flags |= CAIRO_WIN32_SURFACE_CAN_STRETCHDIB;
134
    } else {
135
        int cap;
136
 
137
        cap = GetDeviceCaps(dc, SHADEBLENDCAPS);
138
        if (cap != SB_NONE)
139
            flags |= CAIRO_WIN32_SURFACE_CAN_ALPHABLEND;
140
 
141
        cap = GetDeviceCaps(dc, RASTERCAPS);
142
        if (cap & RC_BITBLT)
143
            flags |= CAIRO_WIN32_SURFACE_CAN_BITBLT;
144
        if (cap & RC_STRETCHBLT)
145
            flags |= CAIRO_WIN32_SURFACE_CAN_STRETCHBLT;
146
        if (cap & RC_STRETCHDIB)
147
            flags |= CAIRO_WIN32_SURFACE_CAN_STRETCHDIB;
148
    }
149
 
150
    return flags;
151
}
152
 
153
static cairo_status_t
154
_create_dc_and_bitmap (cairo_win32_surface_t *surface,
155
                       HDC                    original_dc,
156
                       cairo_format_t         format,
157
                       int                    width,
158
                       int                    height,
159
                       unsigned char        **bits_out,
160
                       int                   *rowstride_out)
161
{
162
    cairo_status_t status;
163
 
164
    BITMAPINFO *bitmap_info = NULL;
165
    struct {
166
        BITMAPINFOHEADER bmiHeader;
167
        RGBQUAD bmiColors[2];
168
    } bmi_stack;
169
    void *bits;
170
 
171
    int num_palette = 0;        /* Quiet GCC */
172
    int i;
173
 
174
    surface->dc = NULL;
175
    surface->bitmap = NULL;
176
    surface->is_dib = FALSE;
177
 
178
    switch (format) {
179
    case CAIRO_FORMAT_ARGB32:
180
    case CAIRO_FORMAT_RGB24:
181
        num_palette = 0;
182
        break;
183
 
184
    case CAIRO_FORMAT_A8:
185
        num_palette = 256;
186
        break;
187
 
188
    case CAIRO_FORMAT_A1:
189
        num_palette = 2;
190
        break;
191
    }
192
 
193
    if (num_palette > 2) {
194
        bitmap_info = _cairo_malloc_ab_plus_c (num_palette, sizeof(RGBQUAD), sizeof(BITMAPINFOHEADER));
195
        if (!bitmap_info)
196
            return _cairo_error (CAIRO_STATUS_NO_MEMORY);
197
    } else {
198
        bitmap_info = (BITMAPINFO *)&bmi_stack;
199
    }
200
 
201
    bitmap_info->bmiHeader.biSize = sizeof (BITMAPINFOHEADER);
202
    bitmap_info->bmiHeader.biWidth = width == 0 ? 1 : width;
203
    bitmap_info->bmiHeader.biHeight = height == 0 ? -1 : - height; /* top-down */
204
    bitmap_info->bmiHeader.biSizeImage = 0;
205
    bitmap_info->bmiHeader.biXPelsPerMeter = PELS_72DPI; /* unused here */
206
    bitmap_info->bmiHeader.biYPelsPerMeter = PELS_72DPI; /* unused here */
207
    bitmap_info->bmiHeader.biPlanes = 1;
208
 
209
    switch (format) {
210
    /* We can't create real RGB24 bitmaps because something seems to
211
     * break if we do, especially if we don't set up an image
212
     * fallback.  It could be a bug with using a 24bpp pixman image
213
     * (and creating one with masks).  So treat them like 32bpp.
214
     * Note: This causes problems when using BitBlt/AlphaBlend/etc!
215
     * see end of file.
216
     */
217
    case CAIRO_FORMAT_RGB24:
218
    case CAIRO_FORMAT_ARGB32:
219
        bitmap_info->bmiHeader.biBitCount = 32;
220
        bitmap_info->bmiHeader.biCompression = BI_RGB;
221
        bitmap_info->bmiHeader.biClrUsed = 0;   /* unused */
222
        bitmap_info->bmiHeader.biClrImportant = 0;
223
        break;
224
 
225
    case CAIRO_FORMAT_A8:
226
        bitmap_info->bmiHeader.biBitCount = 8;
227
        bitmap_info->bmiHeader.biCompression = BI_RGB;
228
        bitmap_info->bmiHeader.biClrUsed = 256;
229
        bitmap_info->bmiHeader.biClrImportant = 0;
230
 
231
        for (i = 0; i < 256; i++) {
232
            bitmap_info->bmiColors[i].rgbBlue = i;
233
            bitmap_info->bmiColors[i].rgbGreen = i;
234
            bitmap_info->bmiColors[i].rgbRed = i;
235
            bitmap_info->bmiColors[i].rgbReserved = 0;
236
        }
237
 
238
        break;
239
 
240
    case CAIRO_FORMAT_A1:
241
        bitmap_info->bmiHeader.biBitCount = 1;
242
        bitmap_info->bmiHeader.biCompression = BI_RGB;
243
        bitmap_info->bmiHeader.biClrUsed = 2;
244
        bitmap_info->bmiHeader.biClrImportant = 0;
245
 
246
        for (i = 0; i < 2; i++) {
247
            bitmap_info->bmiColors[i].rgbBlue = i * 255;
248
            bitmap_info->bmiColors[i].rgbGreen = i * 255;
249
            bitmap_info->bmiColors[i].rgbRed = i * 255;
250
            bitmap_info->bmiColors[i].rgbReserved = 0;
251
        }
252
 
253
        break;
254
    }
255
 
256
    surface->dc = CreateCompatibleDC (original_dc);
257
    if (!surface->dc)
258
        goto FAIL;
259
 
260
    surface->bitmap = CreateDIBSection (surface->dc,
261
                                        bitmap_info,
262
                                        DIB_RGB_COLORS,
263
                                        &bits,
264
                                        NULL, 0);
265
    if (!surface->bitmap)
266
        goto FAIL;
267
 
268
    surface->is_dib = TRUE;
269
 
270
    GdiFlush();
271
 
272
    surface->saved_dc_bitmap = SelectObject (surface->dc,
273
                                             surface->bitmap);
274
    if (!surface->saved_dc_bitmap)
275
        goto FAIL;
276
 
277
    if (bitmap_info && num_palette > 2)
278
        free (bitmap_info);
279
 
280
    if (bits_out)
281
        *bits_out = bits;
282
 
283
    if (rowstride_out) {
284
        /* Windows bitmaps are padded to 32-bit (dword) boundaries */
285
        switch (format) {
286
        case CAIRO_FORMAT_ARGB32:
287
        case CAIRO_FORMAT_RGB24:
288
            *rowstride_out = 4 * width;
289
            break;
290
 
291
        case CAIRO_FORMAT_A8:
292
            *rowstride_out = (width + 3) & ~3;
293
            break;
294
 
295
        case CAIRO_FORMAT_A1:
296
            *rowstride_out = ((width + 31) & ~31) / 8;
297
            break;
298
        }
299
    }
300
 
301
    surface->flags = _cairo_win32_flags_for_dc (surface->dc);
302
 
303
    return CAIRO_STATUS_SUCCESS;
304
 
305
 FAIL:
306
    status = _cairo_win32_print_gdi_error ("_create_dc_and_bitmap");
307
 
308
    if (bitmap_info && num_palette > 2)
309
        free (bitmap_info);
310
 
311
    if (surface->saved_dc_bitmap) {
312
        SelectObject (surface->dc, surface->saved_dc_bitmap);
313
        surface->saved_dc_bitmap = NULL;
314
    }
315
 
316
    if (surface->bitmap) {
317
        DeleteObject (surface->bitmap);
318
        surface->bitmap = NULL;
319
    }
320
 
321
    if (surface->dc) {
322
        DeleteDC (surface->dc);
323
        surface->dc = NULL;
324
    }
325
 
326
    return status;
327
}
328
 
329
static cairo_surface_t *
330
_cairo_win32_surface_create_for_dc (HDC             original_dc,
331
                                    cairo_format_t  format,
332
                                    int             width,
333
                                    int             height)
334
{
335
    cairo_status_t status;
336
    cairo_win32_surface_t *surface;
337
    unsigned char *bits;
338
    int rowstride;
339
 
340
    surface = malloc (sizeof (cairo_win32_surface_t));
341
    if (surface == NULL)
342
        return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
343
 
344
    surface->clip_region = NULL;
345
 
346
    status = _create_dc_and_bitmap (surface, original_dc, format,
347
                                    width, height,
348
                                    &bits, &rowstride);
349
    if (status)
350
        goto FAIL;
351
 
352
    surface->image = cairo_image_surface_create_for_data (bits, format,
353
                                                          width, height, rowstride);
354
    status = surface->image->status;
355
    if (status)
356
        goto FAIL;
357
 
358
    surface->format = format;
359
 
360
    surface->clip_rect.x = 0;
361
    surface->clip_rect.y = 0;
362
    surface->clip_rect.width = width;
363
    surface->clip_rect.height = height;
364
 
365
    surface->initial_clip_rgn = NULL;
366
    surface->had_simple_clip = FALSE;
367
 
368
    surface->extents = surface->clip_rect;
369
    surface->font_subsets = NULL;
370
 
371
    _cairo_surface_init (&surface->base, &cairo_win32_surface_backend,
372
                         _cairo_content_from_format (format));
373
 
374
    return &surface->base;
375
 
376
 FAIL:
377
    if (surface->bitmap) {
378
        SelectObject (surface->dc, surface->saved_dc_bitmap);
379
        DeleteObject (surface->bitmap);
380
        DeleteDC (surface->dc);
381
    }
382
    free (surface);
383
 
384
    return _cairo_surface_create_in_error (status);
385
}
386
 
387
static cairo_surface_t *
388
_cairo_win32_surface_create_similar_internal (void          *abstract_src,
389
                                              cairo_content_t content,
390
                                              int            width,
391
                                              int            height,
392
                                              cairo_bool_t   force_dib)
393
{
394
    cairo_win32_surface_t *src = abstract_src;
395
    cairo_format_t format = _cairo_format_from_content (content);
396
    cairo_surface_t *new_surf = NULL;
397
 
398
    /* We force a DIB always if:
399
     * - we need alpha; or
400
     * - the parent is a DIB; or
401
     * - the parent is for printing (because we don't care about the bit depth at that point)
402
     *
403
     * We also might end up with a DIB even if a DDB is requested if DDB creation failed
404
     * due to out of memory.
405
     */
406
    if (src->is_dib ||
407
        (content & CAIRO_CONTENT_ALPHA) ||
408
        src->base.backend->type == CAIRO_SURFACE_TYPE_WIN32_PRINTING)
409
    {
410
        force_dib = TRUE;
411
    }
412
 
413
    if (!force_dib) {
414
        /* try to create a ddb */
415
        new_surf = cairo_win32_surface_create_with_ddb (src->dc, CAIRO_FORMAT_RGB24, width, height);
416
 
417
        if (new_surf->status != CAIRO_STATUS_SUCCESS)
418
            new_surf = NULL;
419
    }
420
 
421
    if (new_surf == NULL) {
422
        new_surf = _cairo_win32_surface_create_for_dc (src->dc, format, width, height);
423
    }
424
 
425
    return new_surf;
426
}
427
 
428
cairo_surface_t *
429
_cairo_win32_surface_create_similar (void           *abstract_src,
430
                                     cairo_content_t content,
431
                                     int             width,
432
                                     int             height)
433
{
434
    return _cairo_win32_surface_create_similar_internal (abstract_src, content, width, height, FALSE);
435
}
436
 
437
cairo_status_t
438
_cairo_win32_surface_finish (void *abstract_surface)
439
{
440
    cairo_win32_surface_t *surface = abstract_surface;
441
 
442
    if (surface->image)
443
        cairo_surface_destroy (surface->image);
444
 
445
    /* If we created the Bitmap and DC, destroy them */
446
    if (surface->bitmap) {
447
        SelectObject (surface->dc, surface->saved_dc_bitmap);
448
        DeleteObject (surface->bitmap);
449
        DeleteDC (surface->dc);
450
    } else {
451
        _cairo_win32_restore_initial_clip (surface);
452
    }
453
 
454
    if (surface->initial_clip_rgn)
455
        DeleteObject (surface->initial_clip_rgn);
456
 
457
    if (surface->font_subsets != NULL)
458
        _cairo_scaled_font_subsets_destroy (surface->font_subsets);
459
 
460
    return CAIRO_STATUS_SUCCESS;
461
}
462
 
463
static cairo_status_t
464
_cairo_win32_surface_get_subimage (cairo_win32_surface_t  *surface,
465
                                   int                     x,
466
                                   int                     y,
467
                                   int                     width,
468
                                   int                     height,
469
                                   cairo_win32_surface_t **local_out)
470
{
471
    cairo_win32_surface_t *local;
472
    cairo_int_status_t status;
473
    cairo_content_t content = _cairo_content_from_format (surface->format);
474
 
475
    local =
476
        (cairo_win32_surface_t *) _cairo_win32_surface_create_similar_internal
477
        (surface, content, width, height, TRUE);
478
    if (local == NULL)
479
        return CAIRO_INT_STATUS_UNSUPPORTED;
480
    if (local->base.status)
481
        return local->base.status;
482
 
483
    status = CAIRO_INT_STATUS_UNSUPPORTED;
484
 
485
    /* Only BitBlt if the source surface supports it. */
486
    if ((surface->flags & CAIRO_WIN32_SURFACE_CAN_BITBLT) &&
487
        BitBlt (local->dc,
488
                0, 0,
489
                width, height,
490
                surface->dc,
491
                x, y,
492
                SRCCOPY))
493
    {
494
        status = CAIRO_STATUS_SUCCESS;
495
    }
496
 
497
    if (status) {
498
        /* If we failed here, most likely the source or dest doesn't
499
         * support BitBlt/AlphaBlend (e.g. a printer).
500
         * You can't reliably get bits from a printer DC, so just fill in
501
         * the surface as white (common case for printing).
502
         */
503
 
504
        RECT r;
505
        r.left = r.top = 0;
506
        r.right = width;
507
        r.bottom = height;
508
        FillRect(local->dc, &r, (HBRUSH)GetStockObject(WHITE_BRUSH));
509
    }
510
 
511
    *local_out = local;
512
 
513
    return CAIRO_STATUS_SUCCESS;
514
}
515
 
516
static cairo_status_t
517
_cairo_win32_surface_acquire_source_image (void                    *abstract_surface,
518
                                           cairo_image_surface_t  **image_out,
519
                                           void                   **image_extra)
520
{
521
    cairo_win32_surface_t *surface = abstract_surface;
522
    cairo_win32_surface_t *local;
523
    cairo_status_t status;
524
 
525
    if (surface->image) {
526
        *image_out = (cairo_image_surface_t *)surface->image;
527
        *image_extra = NULL;
528
        return CAIRO_STATUS_SUCCESS;
529
    }
530
 
531
    status = _cairo_win32_surface_get_subimage (abstract_surface, 0, 0,
532
                                                surface->extents.width,
533
                                                surface->extents.height, &local);
534
    if (status)
535
        return status;
536
 
537
    *image_out = (cairo_image_surface_t *)local->image;
538
    *image_extra = local;
539
    return CAIRO_STATUS_SUCCESS;
540
}
541
 
542
static void
543
_cairo_win32_surface_release_source_image (void                   *abstract_surface,
544
                                           cairo_image_surface_t  *image,
545
                                           void                   *image_extra)
546
{
547
    cairo_win32_surface_t *local = image_extra;
548
 
549
    if (local)
550
        cairo_surface_destroy ((cairo_surface_t *)local);
551
}
552
 
553
static cairo_status_t
554
_cairo_win32_surface_acquire_dest_image (void                    *abstract_surface,
555
                                         cairo_rectangle_int_t   *interest_rect,
556
                                         cairo_image_surface_t  **image_out,
557
                                         cairo_rectangle_int_t   *image_rect,
558
                                         void                   **image_extra)
559
{
560
    cairo_win32_surface_t *surface = abstract_surface;
561
    cairo_win32_surface_t *local = NULL;
562
    cairo_status_t status;
563
 
564
    if (surface->image) {
565
        GdiFlush();
566
 
567
        *image_out = (cairo_image_surface_t *) surface->image;
568
        *image_extra = NULL;
569
        *image_rect = surface->extents;
570
        return CAIRO_STATUS_SUCCESS;
571
    }
572
 
573
    status = _cairo_win32_surface_get_subimage (abstract_surface,
574
                                                interest_rect->x,
575
                                                interest_rect->y,
576
                                                interest_rect->width,
577
                                                interest_rect->height,
578
                                                &local);
579
    if (status)
580
        return status;
581
 
582
    *image_out = (cairo_image_surface_t *) local->image;
583
    *image_extra = local;
584
    *image_rect = *interest_rect;
585
    return CAIRO_STATUS_SUCCESS;
586
}
587
 
588
static void
589
_cairo_win32_surface_release_dest_image (void                    *abstract_surface,
590
                                         cairo_rectangle_int_t   *interest_rect,
591
                                         cairo_image_surface_t   *image,
592
                                         cairo_rectangle_int_t   *image_rect,
593
                                         void                    *image_extra)
594
{
595
    cairo_win32_surface_t *surface = abstract_surface;
596
    cairo_win32_surface_t *local = image_extra;
597
 
598
    if (!local)
599
        return;
600
 
601
    if (!BitBlt (surface->dc,
602
                 image_rect->x, image_rect->y,
603
                 image_rect->width, image_rect->height,
604
                 local->dc,
605
                 0, 0,
606
                 SRCCOPY))
607
        _cairo_win32_print_gdi_error ("_cairo_win32_surface_release_dest_image");
608
 
609
    cairo_surface_destroy ((cairo_surface_t *)local);
610
}
611
 
612
cairo_status_t
613
_cairo_win32_surface_set_clip_region (void           *abstract_surface,
614
                                      cairo_region_t *region)
615
{
616
    cairo_win32_surface_t *surface = abstract_surface;
617
    cairo_status_t status = CAIRO_STATUS_SUCCESS;
618
 
619
    if (surface->clip_region == region)
620
        return CAIRO_STATUS_SUCCESS;
621
 
622
    cairo_region_destroy (surface->clip_region);
623
    surface->clip_region = cairo_region_reference (region);
624
 
625
    /* The semantics we want is that any clip set by cairo combines
626
     * is intersected with the clip on device context that the
627
     * surface was created for. To implement this, we need to
628
     * save the original clip when first setting a clip on surface.
629
     */
630
 
631
    /* Clear any clip set by cairo, return to the original first */
632
    status = _cairo_win32_restore_initial_clip (surface);
633
 
634
    /* Then combine any new region with it */
635
    if (region) {
636
        cairo_rectangle_int_t extents;
637
        int num_rects;
638
        RGNDATA *data;
639
        size_t data_size;
640
        RECT *rects;
641
        int i;
642
        HRGN gdi_region;
643
 
644
        /* Create a GDI region for the cairo region */
645
 
646
        cairo_region_get_extents (region, &extents);
647
        num_rects = cairo_region_num_rectangles (region);
648
        /* XXX see notes in _cairo_win32_save_initial_clip --
649
         * this code will interact badly with a HDC which had an initial
650
         * world transform -- we should probably manually transform the
651
         * region rects, because SelectClipRgn takes device units, not
652
         * logical units (unlike IntersectClipRect).
653
         */
654
 
655
        data_size = sizeof (RGNDATAHEADER) + num_rects * sizeof (RECT);
656
        data = malloc (data_size);
657
        if (!data)
658
            return _cairo_error(CAIRO_STATUS_NO_MEMORY);
659
        rects = (RECT *)data->Buffer;
660
 
661
        data->rdh.dwSize = sizeof (RGNDATAHEADER);
662
        data->rdh.iType = RDH_RECTANGLES;
663
        data->rdh.nCount = num_rects;
664
        data->rdh.nRgnSize = num_rects * sizeof (RECT);
665
        data->rdh.rcBound.left = extents.x;
666
        data->rdh.rcBound.top = extents.y;
667
        data->rdh.rcBound.right = extents.x + extents.width;
668
        data->rdh.rcBound.bottom = extents.y + extents.height;
669
 
670
        for (i = 0; i < num_rects; i++) {
671
            cairo_rectangle_int_t rect;
672
 
673
            cairo_region_get_rectangle (region, i, &rect);
674
 
675
            rects[i].left   = rect.x;
676
            rects[i].top    = rect.y;
677
            rects[i].right  = rect.x + rect.width;
678
            rects[i].bottom = rect.y + rect.height;
679
        }
680
 
681
        gdi_region = ExtCreateRegion (NULL, data_size, data);
682
        free (data);
683
 
684
        if (!gdi_region)
685
            return _cairo_error (CAIRO_STATUS_NO_MEMORY);
686
 
687
        /* AND the new region into our DC */
688
        if (ExtSelectClipRgn (surface->dc, gdi_region, RGN_AND) == ERROR)
689
            status = _cairo_win32_print_gdi_error ("_cairo_win32_surface_set_clip_region");
690
 
691
        DeleteObject (gdi_region);
692
    }
693
 
694
    return status;
695
}
696
 
697
#if !defined(AC_SRC_OVER)
698
#define AC_SRC_OVER                 0x00
699
#pragma pack(1)
700
typedef struct {
701
    BYTE   BlendOp;
702
    BYTE   BlendFlags;
703
    BYTE   SourceConstantAlpha;
704
    BYTE   AlphaFormat;
705
}BLENDFUNCTION;
706
#pragma pack()
707
#endif
708
 
709
/* for compatibility with VC++ 6 */
710
#ifndef AC_SRC_ALPHA
711
#define AC_SRC_ALPHA                0x01
712
#endif
713
 
714
typedef BOOL (WINAPI *cairo_alpha_blend_func_t) (HDC hdcDest,
715
                                                 int nXOriginDest,
716
                                                 int nYOriginDest,
717
                                                 int nWidthDest,
718
                                                 int hHeightDest,
719
                                                 HDC hdcSrc,
720
                                                 int nXOriginSrc,
721
                                                 int nYOriginSrc,
722
                                                 int nWidthSrc,
723
                                                 int nHeightSrc,
724
                                                 BLENDFUNCTION blendFunction);
725
 
726
static cairo_int_status_t
727
_composite_alpha_blend (cairo_win32_surface_t *dst,
728
                        cairo_win32_surface_t *src,
729
                        int                    alpha,
730
                        int                    src_x,
731
                        int                    src_y,
732
                        int                    src_w,
733
                        int                    src_h,
734
                        int                    dst_x,
735
                        int                    dst_y,
736
                        int                    dst_w,
737
                        int                    dst_h)
738
{
739
    static unsigned alpha_blend_checked = FALSE;
740
    static cairo_alpha_blend_func_t alpha_blend = NULL;
741
 
742
    BLENDFUNCTION blend_function;
743
 
744
    /* Check for AlphaBlend dynamically to allow compiling on
745
     * MSVC 6 and use on older windows versions
746
     */
747
    if (!alpha_blend_checked) {
748
        OSVERSIONINFO os;
749
 
750
        os.dwOSVersionInfoSize = sizeof (os);
751
        GetVersionEx (&os);
752
 
753
        /* If running on Win98, disable using AlphaBlend()
754
         * to avoid Win98 AlphaBlend() bug */
755
        if (VER_PLATFORM_WIN32_WINDOWS != os.dwPlatformId ||
756
            os.dwMajorVersion != 4 || os.dwMinorVersion != 10)
757
        {
758
            HMODULE msimg32_dll = LoadLibraryW (L"msimg32");
759
 
760
            if (msimg32_dll != NULL)
761
                alpha_blend = (cairo_alpha_blend_func_t)GetProcAddress (msimg32_dll,
762
                                                                        "AlphaBlend");
763
        }
764
 
765
        alpha_blend_checked = TRUE;
766
    }
767
 
768
    if (alpha_blend == NULL)
769
        return CAIRO_INT_STATUS_UNSUPPORTED;
770
    if (!(dst->flags & CAIRO_WIN32_SURFACE_CAN_ALPHABLEND))
771
        return CAIRO_INT_STATUS_UNSUPPORTED;
772
    if (src->format == CAIRO_FORMAT_RGB24 && dst->format == CAIRO_FORMAT_ARGB32)
773
        return CAIRO_INT_STATUS_UNSUPPORTED;
774
 
775
    blend_function.BlendOp = AC_SRC_OVER;
776
    blend_function.BlendFlags = 0;
777
    blend_function.SourceConstantAlpha = alpha;
778
    blend_function.AlphaFormat = (src->format == CAIRO_FORMAT_ARGB32) ? AC_SRC_ALPHA : 0;
779
 
780
    if (!alpha_blend (dst->dc,
781
                      dst_x, dst_y,
782
                      dst_w, dst_h,
783
                      src->dc,
784
                      src_x, src_y,
785
                      src_w, src_h,
786
                      blend_function))
787
        return _cairo_win32_print_gdi_error ("_cairo_win32_surface_composite(AlphaBlend)");
788
 
789
    return CAIRO_STATUS_SUCCESS;
790
}
791
 
792
static cairo_int_status_t
793
_cairo_win32_surface_composite_inner (cairo_win32_surface_t *src,
794
                                      cairo_image_surface_t *src_image,
795
                                      cairo_win32_surface_t *dst,
796
                                      cairo_rectangle_int_t src_extents,
797
                                      cairo_rectangle_int_t src_r,
798
                                      cairo_rectangle_int_t dst_r,
799
                                      int alpha,
800
                                      cairo_bool_t needs_alpha,
801
                                      cairo_bool_t needs_scale)
802
{
803
    /* Then do BitBlt, StretchDIBits, StretchBlt, AlphaBlend, or MaskBlt */
804
    if (src_image) {
805
        if (needs_alpha || needs_scale)
806
            return CAIRO_INT_STATUS_UNSUPPORTED;
807
 
808
        if (dst->flags & CAIRO_WIN32_SURFACE_CAN_STRETCHBLT) {
809
            BITMAPINFO bi;
810
            bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
811
            bi.bmiHeader.biWidth = src_image->width;
812
            bi.bmiHeader.biHeight = - src_image->height;
813
            bi.bmiHeader.biSizeImage = 0;
814
            bi.bmiHeader.biXPelsPerMeter = PELS_72DPI;
815
            bi.bmiHeader.biYPelsPerMeter = PELS_72DPI;
816
            bi.bmiHeader.biPlanes = 1;
817
            bi.bmiHeader.biBitCount = 32;
818
            bi.bmiHeader.biCompression = BI_RGB;
819
            bi.bmiHeader.biClrUsed = 0;
820
            bi.bmiHeader.biClrImportant = 0;
821
 
822
            /* StretchDIBits is broken with top-down dibs; you need to do some
823
             * special munging to make the coordinate space work (basically,
824
             * need to address everything based on the bottom left, instead of top left,
825
             * and need to tell it to flip the resulting image.
826
             *
827
             * See http://blog.vlad1.com/archives/2006/10/26/134/ and comments.
828
             */
829
            if (!StretchDIBits (dst->dc,
830
                                /* dst x,y,w,h */
831
                                dst_r.x, dst_r.y + dst_r.height - 1,
832
                                dst_r.width, - (int) dst_r.height,
833
                                /* src x,y,w,h */
834
                                src_r.x, src_extents.height - src_r.y + 1,
835
                                src_r.width, - (int) src_r.height,
836
                                src_image->data,
837
                                &bi,
838
                                DIB_RGB_COLORS,
839
                                SRCCOPY))
840
                return _cairo_win32_print_gdi_error ("_cairo_win32_surface_composite(StretchDIBits)");
841
        }
842
    } else if (!needs_alpha) {
843
        /* BitBlt or StretchBlt? */
844
        if (!needs_scale && (dst->flags & CAIRO_WIN32_SURFACE_CAN_BITBLT)) {
845
            if (!BitBlt (dst->dc,
846
                         dst_r.x, dst_r.y,
847
                         dst_r.width, dst_r.height,
848
                         src->dc,
849
                         src_r.x, src_r.y,
850
                         SRCCOPY))
851
                return _cairo_win32_print_gdi_error ("_cairo_win32_surface_composite(BitBlt)");
852
        } else if (dst->flags & CAIRO_WIN32_SURFACE_CAN_STRETCHBLT) {
853
            /* StretchBlt? */
854
            /* XXX check if we want HALFTONE, based on the src filter */
855
            BOOL success;
856
            int oldmode = SetStretchBltMode(dst->dc, HALFTONE);
857
            success = StretchBlt(dst->dc,
858
                                 dst_r.x, dst_r.y,
859
                                 dst_r.width, dst_r.height,
860
                                 src->dc,
861
                                 src_r.x, src_r.y,
862
                                 src_r.width, src_r.height,
863
                                 SRCCOPY);
864
            SetStretchBltMode(dst->dc, oldmode);
865
 
866
            if (!success)
867
                return _cairo_win32_print_gdi_error ("StretchBlt");
868
        }
869
    } else if (needs_alpha && !needs_scale) {
870
        return _composite_alpha_blend (dst, src, alpha,
871
                                       src_r.x, src_r.y, src_r.width, src_r.height,
872
                                       dst_r.x, dst_r.y, dst_r.width, dst_r.height);
873
    }
874
 
875
    return CAIRO_STATUS_SUCCESS;
876
}
877
 
878
/* from pixman-private.h */
879
#define MOD(a,b) ((a) < 0 ? ((b) - ((-(a) - 1) % (b))) - 1 : (a) % (b))
880
 
881
static cairo_int_status_t
882
_cairo_win32_surface_composite (cairo_operator_t        op,
883
                                const cairo_pattern_t   *pattern,
884
                                const cairo_pattern_t   *mask_pattern,
885
                                void                    *abstract_dst,
886
                                int                     src_x,
887
                                int                     src_y,
888
                                int                     mask_x,
889
                                int                     mask_y,
890
                                int                     dst_x,
891
                                int                     dst_y,
892
                                unsigned int            width,
893
                                unsigned int            height,
894
                                cairo_region_t         *clip_region)
895
{
896
    cairo_win32_surface_t *dst = abstract_dst;
897
    cairo_win32_surface_t *src;
898
    cairo_surface_pattern_t *src_surface_pattern;
899
    int alpha;
900
    double scalex, scaley;
901
    cairo_fixed_t x0_fixed, y0_fixed;
902
    cairo_int_status_t status;
903
 
904
    cairo_bool_t needs_alpha, needs_scale, needs_repeat;
905
    cairo_image_surface_t *src_image = NULL;
906
 
907
    cairo_format_t src_format;
908
    cairo_rectangle_int_t src_extents;
909
 
910
    cairo_rectangle_int_t src_r = { src_x, src_y, width, height };
911
    cairo_rectangle_int_t dst_r = { dst_x, dst_y, width, height };
912
 
913
#ifdef DEBUG_COMPOSITE
914
    fprintf (stderr, "+++ composite: %d %p %p %p [%d %d] [%d %d] [%d %d] %dx%d\n",
915
             op, pattern, mask_pattern, abstract_dst, src_x, src_y, mask_x, mask_y, dst_x, dst_y, width, height);
916
#endif
917
 
918
    /* If the destination can't do any of these, then
919
     * we may as well give up, since this is what we'll
920
     * look to for optimization.
921
     */
922
    if ((dst->flags & (CAIRO_WIN32_SURFACE_CAN_BITBLT |
923
                       CAIRO_WIN32_SURFACE_CAN_ALPHABLEND |
924
                       CAIRO_WIN32_SURFACE_CAN_STRETCHBLT |
925
                       CAIRO_WIN32_SURFACE_CAN_STRETCHDIB))
926
        == 0)
927
    {
928
        goto UNSUPPORTED;
929
    }
930
 
931
    if (pattern->type != CAIRO_PATTERN_TYPE_SURFACE)
932
        goto UNSUPPORTED;
933
 
934
    if (pattern->extend != CAIRO_EXTEND_NONE &&
935
        pattern->extend != CAIRO_EXTEND_REPEAT)
936
        goto UNSUPPORTED;
937
 
938
    if (mask_pattern) {
939
        /* FIXME: When we fully support RENDER style 4-channel
940
         * masks we need to check r/g/b != 1.0.
941
         */
942
        if (mask_pattern->type != CAIRO_PATTERN_TYPE_SOLID)
943
            return CAIRO_INT_STATUS_UNSUPPORTED;
944
 
945
        alpha = ((cairo_solid_pattern_t *)mask_pattern)->color.alpha_short >> 8;
946
    } else {
947
        alpha = 255;
948
    }
949
 
950
    src_surface_pattern = (cairo_surface_pattern_t *)pattern;
951
    src = (cairo_win32_surface_t *)src_surface_pattern->surface;
952
 
953
    if (src->base.type == CAIRO_SURFACE_TYPE_IMAGE &&
954
        dst->flags & (CAIRO_WIN32_SURFACE_CAN_STRETCHDIB))
955
    {
956
        /* In some very limited cases, we can use StretchDIBits to draw
957
         * an image surface directly:
958
         *  - source is CAIRO_FORMAT_ARGB32
959
         *  - dest is CAIRO_FORMAT_ARGB32
960
         *  - alpha is 255
961
         *  - operator is SOURCE or OVER
962
         *  - image stride is 4*width
963
         */
964
        src_image = (cairo_image_surface_t*) src;
965
 
966
        if (src_image->format != CAIRO_FORMAT_RGB24 ||
967
            dst->format != CAIRO_FORMAT_RGB24 ||
968
            alpha != 255 ||
969
            (op != CAIRO_OPERATOR_SOURCE && op != CAIRO_OPERATOR_OVER) ||
970
            src_image->stride != (src_image->width * 4))
971
        {
972
            goto UNSUPPORTED;
973
        }
974
 
975
        src_format = src_image->format;
976
        src_extents.x = 0;
977
        src_extents.y = 0;
978
        src_extents.width = src_image->width;
979
        src_extents.height = src_image->height;
980
    } else if (src->base.backend != dst->base.backend) {
981
        goto UNSUPPORTED;
982
    } else {
983
        src_format = src->format;
984
        src_extents = src->extents;
985
    }
986
 
987
 
988
#ifdef DEBUG_COMPOSITE
989
    fprintf (stderr, "Before check: src size: (%d %d) xy [%d %d] -> dst [%d %d %d %d] {srcmat %f %f %f %f}\n",
990
             src_extents.width, src_extents.height,
991
             src_x, src_y,
992
             dst_x, dst_y, width, height,
993
             pattern->matrix.x0, pattern->matrix.y0, pattern->matrix.xx, pattern->matrix.yy);
994
#endif
995
 
996
    /* We can only use GDI functions if the source and destination rectangles
997
     * are on integer pixel boundaries.  Figure that out here.
998
     */
999
    x0_fixed = _cairo_fixed_from_double(pattern->matrix.x0 / pattern->matrix.xx);
1000
    y0_fixed = _cairo_fixed_from_double(pattern->matrix.y0 / pattern->matrix.yy);
1001
 
1002
    if (pattern->matrix.yx != 0.0 ||
1003
        pattern->matrix.xy != 0.0 ||
1004
        !_cairo_fixed_is_integer(x0_fixed) ||
1005
        !_cairo_fixed_is_integer(y0_fixed))
1006
    {
1007
        goto UNSUPPORTED;
1008
    }
1009
 
1010
    scalex = pattern->matrix.xx;
1011
    scaley = pattern->matrix.yy;
1012
 
1013
    src_r.x += _cairo_fixed_integer_part(x0_fixed);
1014
    src_r.y += _cairo_fixed_integer_part(y0_fixed);
1015
 
1016
    /* Success, right? */
1017
    if (scalex == 0.0 || scaley == 0.0)
1018
        return CAIRO_STATUS_SUCCESS;
1019
 
1020
    if (scalex != 1.0 || scaley != 1.0)
1021
        goto UNSUPPORTED;
1022
 
1023
    /* If the src coordinates are outside of the source surface bounds,
1024
     * we have to fix them up, because this is an error for the GDI
1025
     * functions.
1026
     */
1027
 
1028
#ifdef DEBUG_COMPOSITE
1029
    fprintf (stderr, "before: [%d %d %d %d] -> [%d %d %d %d]\n",
1030
             src_r.x, src_r.y, src_r.width, src_r.height,
1031
             dst_r.x, dst_r.y, dst_r.width, dst_r.height);
1032
    fflush (stderr);
1033
#endif
1034
 
1035
    /* If the src rectangle doesn't wholly lie within the src extents,
1036
     * fudge things.  We really need to do fixup on the unpainted
1037
     * region -- e.g. the SOURCE operator is broken for areas outside
1038
     * of the extents, because it won't clear that area to transparent
1039
     * black.
1040
     */
1041
 
1042
    if (pattern->extend != CAIRO_EXTEND_REPEAT) {
1043
        needs_repeat = FALSE;
1044
 
1045
        /* If the src rect and the extents of the source image don't overlap at all,
1046
         * we can't do anything useful here.
1047
         */
1048
        if (src_r.x > src_extents.width || src_r.y > src_extents.height ||
1049
            (src_r.x + src_r.width) < 0 || (src_r.y + src_r.height) < 0)
1050
        {
1051
            if (op == CAIRO_OPERATOR_OVER)
1052
                return CAIRO_STATUS_SUCCESS;
1053
            goto UNSUPPORTED;
1054
        }
1055
 
1056
        if (src_r.x < 0) {
1057
            src_r.width += src_r.x;
1058
            src_r.x = 0;
1059
 
1060
            dst_r.width += src_r.x;
1061
            dst_r.x -= src_r.x;
1062
        }
1063
 
1064
        if (src_r.y < 0) {
1065
            src_r.height += src_r.y;
1066
            src_r.y = 0;
1067
 
1068
            dst_r.height += dst_r.y;
1069
            dst_r.y -= src_r.y;
1070
        }
1071
 
1072
        if (src_r.x + src_r.width > src_extents.width) {
1073
            src_r.width = src_extents.width - src_r.x;
1074
            dst_r.width = src_r.width;
1075
        }
1076
 
1077
        if (src_r.y + src_r.height > src_extents.height) {
1078
            src_r.height = src_extents.height - src_r.y;
1079
            dst_r.height = src_r.height;
1080
        }
1081
    } else {
1082
        needs_repeat = TRUE;
1083
    }
1084
 
1085
    /*
1086
     * Operations that we can do:
1087
     *
1088
     *  RGB OVER  RGB -> BitBlt (same as SOURCE)
1089
     *  RGB OVER ARGB -> UNSUPPORTED (AlphaBlend treats this as a BitBlt, even with SCA 255 and no AC_SRC_ALPHA)
1090
     * ARGB OVER ARGB -> AlphaBlend, with AC_SRC_ALPHA
1091
     * ARGB OVER  RGB -> AlphaBlend, with AC_SRC_ALPHA; we'll have junk in the dst A byte
1092
     *
1093
     *  RGB OVER  RGB + mask -> AlphaBlend, no AC_SRC_ALPHA
1094
     *  RGB OVER ARGB + mask -> UNSUPPORTED
1095
     * ARGB OVER ARGB + mask -> AlphaBlend, with AC_SRC_ALPHA
1096
     * ARGB OVER  RGB + mask -> AlphaBlend, with AC_SRC_ALPHA; junk in the dst A byte
1097
     *
1098
     *  RGB SOURCE  RGB -> BitBlt
1099
     *  RGB SOURCE ARGB -> UNSUPPORTED (AlphaBlend treats this as a BitBlt, even with SCA 255 and no AC_SRC_ALPHA)
1100
     * ARGB SOURCE ARGB -> BitBlt
1101
     * ARGB SOURCE  RGB -> BitBlt
1102
     *
1103
     *  RGB SOURCE  RGB + mask -> unsupported
1104
     *  RGB SOURCE ARGB + mask -> unsupported
1105
     * ARGB SOURCE ARGB + mask -> unsupported
1106
     * ARGB SOURCE  RGB + mask -> unsupported
1107
     */
1108
 
1109
    /*
1110
     * Figure out what action to take.
1111
     */
1112
    if (op == CAIRO_OPERATOR_OVER) {
1113
        if (alpha == 0)
1114
            return CAIRO_STATUS_SUCCESS;
1115
 
1116
        if (src_format == dst->format) {
1117
            if (alpha == 255 && src_format == CAIRO_FORMAT_RGB24) {
1118
                needs_alpha = FALSE;
1119
            } else {
1120
                needs_alpha = TRUE;
1121
            }
1122
        } else if (src_format == CAIRO_FORMAT_ARGB32 &&
1123
                   dst->format == CAIRO_FORMAT_RGB24)
1124
        {
1125
            needs_alpha = TRUE;
1126
        } else {
1127
            goto UNSUPPORTED;
1128
        }
1129
    } else if (alpha == 255 && op == CAIRO_OPERATOR_SOURCE) {
1130
        if ((src_format == dst->format) ||
1131
            (src_format == CAIRO_FORMAT_ARGB32 && dst->format == CAIRO_FORMAT_RGB24))
1132
        {
1133
            needs_alpha = FALSE;
1134
        } else {
1135
            goto UNSUPPORTED;
1136
        }
1137
    } else {
1138
        goto UNSUPPORTED;
1139
    }
1140
 
1141
    if (scalex == 1.0 && scaley == 1.0) {
1142
        needs_scale = FALSE;
1143
    } else {
1144
        /* Should never be reached until we turn StretchBlt back on */
1145
        needs_scale = TRUE;
1146
    }
1147
 
1148
#ifdef DEBUG_COMPOSITE
1149
    fprintf (stderr, "action: [%d %d %d %d] -> [%d %d %d %d]\n",
1150
             src_r.x, src_r.y, src_r.width, src_r.height,
1151
             dst_r.x, dst_r.y, dst_r.width, dst_r.height);
1152
    fflush (stderr);
1153
#endif
1154
 
1155
    status = _cairo_win32_surface_set_clip_region (dst, clip_region);
1156
    if (status)
1157
        return status;
1158
 
1159
    /* If we need to repeat, we turn the repeated blit into
1160
     * a bunch of piece-by-piece blits.
1161
     */
1162
    if (needs_repeat) {
1163
        cairo_rectangle_int_t piece_src_r, piece_dst_r;
1164
        uint32_t rendered_width = 0, rendered_height = 0;
1165
        uint32_t to_render_height, to_render_width;
1166
        int32_t piece_x, piece_y;
1167
        int32_t src_start_x = MOD(src_r.x, src_extents.width);
1168
        int32_t src_start_y = MOD(src_r.y, src_extents.height);
1169
 
1170
        if (needs_scale)
1171
            goto UNSUPPORTED;
1172
 
1173
        /* If both the src and dest have an image, we may as well fall
1174
         * back, because it will be faster than our separate blits.
1175
         * Our blit code will be fastest when the src is a DDB and the
1176
         * destination is a DDB.
1177
         */
1178
        if ((src_image || src->image) && dst->image)
1179
            goto UNSUPPORTED;
1180
 
1181
        /* If the src is not a bitmap but an on-screen (or unknown)
1182
         * DC, chances are that fallback will be faster.
1183
         */
1184
        if (src->bitmap == NULL)
1185
            goto UNSUPPORTED;
1186
 
1187
        /* If we can use PatBlt, just do so */
1188
        if (!src_image && !needs_alpha)
1189
        {
1190
            HBRUSH brush;
1191
            HGDIOBJ old_brush;
1192
            POINT old_brush_origin;
1193
 
1194
            /* Set up the brush with our bitmap */
1195
            brush = CreatePatternBrush (src->bitmap);
1196
 
1197
            /* SetBrushOrgEx sets the coordinates in the destination DC of where the
1198
             * pattern should start.
1199
             */
1200
            SetBrushOrgEx (dst->dc, dst_r.x - src_start_x,
1201
                           dst_r.y - src_start_y, &old_brush_origin);
1202
 
1203
            old_brush = SelectObject (dst->dc, brush);
1204
 
1205
            PatBlt (dst->dc, dst_r.x, dst_r.y, dst_r.width, dst_r.height, PATCOPY);
1206
 
1207
            /* Restore the old brush and pen */
1208
            SetBrushOrgEx (dst->dc, old_brush_origin.x, old_brush_origin.y, NULL);
1209
            SelectObject (dst->dc, old_brush);
1210
            DeleteObject (brush);
1211
 
1212
            return CAIRO_STATUS_SUCCESS;
1213
        }
1214
 
1215
        /* If we were not able to use PatBlt, then manually expand out the blit */
1216
 
1217
        /* Arbitrary factor; we think that going through
1218
         * fallback will be faster if we have to do more
1219
         * than this amount of blits in either direction.
1220
         */
1221
        if (dst_r.width / src_extents.width > 5 ||
1222
            dst_r.height / src_extents.height > 5)
1223
            goto UNSUPPORTED;
1224
 
1225
        for (rendered_height = 0;
1226
             rendered_height < dst_r.height;
1227
             rendered_height += to_render_height)
1228
        {
1229
            piece_y = (src_start_y + rendered_height) % src_extents.height;
1230
            to_render_height = src_extents.height - piece_y;
1231
 
1232
            if (rendered_height + to_render_height > dst_r.height)
1233
                to_render_height = dst_r.height - rendered_height;
1234
 
1235
            for (rendered_width = 0;
1236
                 rendered_width < dst_r.width;
1237
                 rendered_width += to_render_width)
1238
            {
1239
                piece_x = (src_start_x + rendered_width) % src_extents.width;
1240
                to_render_width = src_extents.width - piece_x;
1241
 
1242
                if (rendered_width + to_render_width > dst_r.width)
1243
                    to_render_width = dst_r.width - rendered_width;
1244
 
1245
                piece_src_r.x = piece_x;
1246
                piece_src_r.y = piece_y;
1247
                piece_src_r.width = to_render_width;
1248
                piece_src_r.height = to_render_height;
1249
 
1250
                piece_dst_r.x = dst_r.x + rendered_width;
1251
                piece_dst_r.y = dst_r.y + rendered_height;
1252
                piece_dst_r.width = to_render_width;
1253
                piece_dst_r.height = to_render_height;
1254
 
1255
                status = _cairo_win32_surface_composite_inner (src, src_image, dst,
1256
                                                               src_extents, piece_src_r, piece_dst_r,
1257
                                                               alpha, needs_alpha, needs_scale);
1258
                if (status != CAIRO_STATUS_SUCCESS) {
1259
                    /* Uh oh.  If something failed, and it's the first
1260
                     * piece, then we can jump to UNSUPPORTED.
1261
                     * Otherwise, this is bad times, because part of the
1262
                     * rendering was already done. */
1263
                    if (rendered_width == 0 &&
1264
                        rendered_height == 0)
1265
                    {
1266
                        goto UNSUPPORTED;
1267
                    }
1268
 
1269
                    return status;
1270
                }
1271
            }
1272
        }
1273
    } else {
1274
        status = _cairo_win32_surface_composite_inner (src, src_image, dst,
1275
                                                       src_extents, src_r, dst_r,
1276
                                                       alpha, needs_alpha, needs_scale);
1277
    }
1278
 
1279
    if (status == CAIRO_STATUS_SUCCESS)
1280
        return status;
1281
 
1282
UNSUPPORTED:
1283
    /* Fall back to image surface directly, if this is a DIB surface */
1284
    if (dst->image) {
1285
        GdiFlush();
1286
 
1287
        return dst->image->backend->composite (op, pattern, mask_pattern,
1288
                                               dst->image,
1289
                                               src_x, src_y,
1290
                                               mask_x, mask_y,
1291
                                               dst_x, dst_y,
1292
                                               width, height,
1293
                                               clip_region);
1294
    }
1295
 
1296
    return CAIRO_INT_STATUS_UNSUPPORTED;
1297
}
1298
 
1299
/* This big function tells us how to optimize operators for the
1300
 * case of solid destination and constant-alpha source
1301
 *
1302
 * Note: This function needs revisiting if we add support for
1303
 *       super-luminescent colors (a == 0, r,g,b > 0)
1304
 */
1305
static enum { DO_CLEAR, DO_SOURCE, DO_NOTHING, DO_UNSUPPORTED }
1306
categorize_solid_dest_operator (cairo_operator_t op,
1307
                                unsigned short   alpha)
1308
{
1309
    enum { SOURCE_TRANSPARENT, SOURCE_LIGHT, SOURCE_SOLID, SOURCE_OTHER } source;
1310
 
1311
    if (alpha >= 0xff00)
1312
        source = SOURCE_SOLID;
1313
    else if (alpha < 0x100)
1314
        source = SOURCE_TRANSPARENT;
1315
    else
1316
        source = SOURCE_OTHER;
1317
 
1318
    switch (op) {
1319
    case CAIRO_OPERATOR_CLEAR:    /* 0                 0 */
1320
    case CAIRO_OPERATOR_OUT:      /* 1 - Ab            0 */
1321
        return DO_CLEAR;
1322
        break;
1323
 
1324
    case CAIRO_OPERATOR_SOURCE:   /* 1                 0 */
1325
    case CAIRO_OPERATOR_IN:       /* Ab                0 */
1326
        return DO_SOURCE;
1327
        break;
1328
 
1329
    case CAIRO_OPERATOR_OVER:     /* 1            1 - Aa */
1330
    case CAIRO_OPERATOR_ATOP:     /* Ab           1 - Aa */
1331
        if (source == SOURCE_SOLID)
1332
            return DO_SOURCE;
1333
        else if (source == SOURCE_TRANSPARENT)
1334
            return DO_NOTHING;
1335
        else
1336
            return DO_UNSUPPORTED;
1337
        break;
1338
 
1339
    case CAIRO_OPERATOR_DEST_OUT: /* 0            1 - Aa */
1340
    case CAIRO_OPERATOR_XOR:      /* 1 - Ab       1 - Aa */
1341
        if (source == SOURCE_SOLID)
1342
            return DO_CLEAR;
1343
        else if (source == SOURCE_TRANSPARENT)
1344
            return DO_NOTHING;
1345
        else
1346
            return DO_UNSUPPORTED;
1347
        break;
1348
 
1349
    case CAIRO_OPERATOR_DEST:     /* 0                 1 */
1350
    case CAIRO_OPERATOR_DEST_OVER:/* 1 - Ab            1 */
1351
    case CAIRO_OPERATOR_SATURATE: /* min(1,(1-Ab)/Aa)  1 */
1352
        return DO_NOTHING;
1353
        break;
1354
 
1355
    case CAIRO_OPERATOR_DEST_IN:  /* 0                Aa */
1356
    case CAIRO_OPERATOR_DEST_ATOP:/* 1 - Ab           Aa */
1357
        if (source == SOURCE_SOLID)
1358
            return DO_NOTHING;
1359
        else if (source == SOURCE_TRANSPARENT)
1360
            return DO_CLEAR;
1361
        else
1362
            return DO_UNSUPPORTED;
1363
        break;
1364
 
1365
    case CAIRO_OPERATOR_ADD:      /* 1                1 */
1366
        if (source == SOURCE_TRANSPARENT)
1367
            return DO_NOTHING;
1368
        else
1369
            return DO_UNSUPPORTED;
1370
        break;
1371
    }
1372
 
1373
    ASSERT_NOT_REACHED;
1374
    return DO_UNSUPPORTED;
1375
}
1376
 
1377
static cairo_int_status_t
1378
_cairo_win32_surface_fill_rectangles (void                      *abstract_surface,
1379
                                      cairo_operator_t          op,
1380
                                      const cairo_color_t       *color,
1381
                                      cairo_rectangle_int_t     *rects,
1382
                                      int                       num_rects)
1383
{
1384
    cairo_win32_surface_t *surface = abstract_surface;
1385
    cairo_status_t status;
1386
    COLORREF new_color;
1387
    HBRUSH new_brush;
1388
    int i;
1389
 
1390
    /* XXXperf If it's not RGB24, we need to do a little more checking
1391
     * to figure out when we can use GDI.  We don't have that checking
1392
     * anywhere at the moment, so just bail and use the fallback
1393
     * paths. */
1394
    if (surface->format != CAIRO_FORMAT_RGB24)
1395
        return CAIRO_INT_STATUS_UNSUPPORTED;
1396
 
1397
    status = _cairo_win32_surface_set_clip_region (surface, NULL);
1398
    if (status)
1399
        return status;
1400
 
1401
    /* Optimize for no destination alpha (surface->pixman_image is non-NULL for all
1402
     * surfaces with alpha.)
1403
     */
1404
    switch (categorize_solid_dest_operator (op, color->alpha_short)) {
1405
    case DO_CLEAR:
1406
        new_color = RGB (0, 0, 0);
1407
        break;
1408
    case DO_SOURCE:
1409
        new_color = RGB (color->red_short >> 8, color->green_short >> 8, color->blue_short >> 8);
1410
        break;
1411
    case DO_NOTHING:
1412
        return CAIRO_STATUS_SUCCESS;
1413
    case DO_UNSUPPORTED:
1414
    default:
1415
        return CAIRO_INT_STATUS_UNSUPPORTED;
1416
    }
1417
 
1418
    new_brush = CreateSolidBrush (new_color);
1419
    if (!new_brush)
1420
        return _cairo_win32_print_gdi_error ("_cairo_win32_surface_fill_rectangles");
1421
 
1422
    for (i = 0; i < num_rects; i++) {
1423
        RECT rect;
1424
 
1425
        rect.left = rects[i].x;
1426
        rect.top = rects[i].y;
1427
        rect.right = rects[i].x + rects[i].width;
1428
        rect.bottom = rects[i].y + rects[i].height;
1429
 
1430
        if (!FillRect (surface->dc, &rect, new_brush))
1431
            goto FAIL;
1432
    }
1433
 
1434
    DeleteObject (new_brush);
1435
 
1436
    return CAIRO_STATUS_SUCCESS;
1437
 
1438
 FAIL:
1439
    status = _cairo_win32_print_gdi_error ("_cairo_win32_surface_fill_rectangles");
1440
 
1441
    DeleteObject (new_brush);
1442
 
1443
    return status;
1444
}
1445
 
1446
cairo_bool_t
1447
_cairo_win32_surface_get_extents (void                    *abstract_surface,
1448
                                  cairo_rectangle_int_t   *rectangle)
1449
{
1450
    cairo_win32_surface_t *surface = abstract_surface;
1451
 
1452
    *rectangle = surface->extents;
1453
    return TRUE;
1454
}
1455
 
1456
static cairo_status_t
1457
_cairo_win32_surface_flush (void *abstract_surface)
1458
{
1459
    return _cairo_win32_surface_set_clip_region (abstract_surface, NULL);
1460
}
1461
 
1462
#define STACK_GLYPH_SIZE 256
1463
 
1464
cairo_int_status_t
1465
_cairo_win32_surface_show_glyphs (void                  *surface,
1466
                                  cairo_operator_t       op,
1467
                                  const cairo_pattern_t *source,
1468
                                  cairo_glyph_t         *glyphs,
1469
                                  int                    num_glyphs,
1470
                                  cairo_scaled_font_t   *scaled_font,
1471
                                  cairo_clip_t          *clip,
1472
                                  int                   *remaining_glyphs)
1473
{
1474
#if CAIRO_HAS_WIN32_FONT
1475
    cairo_win32_surface_t *dst = surface;
1476
 
1477
    WORD glyph_buf_stack[STACK_GLYPH_SIZE];
1478
    WORD *glyph_buf = glyph_buf_stack;
1479
    int dxy_buf_stack[2 * STACK_GLYPH_SIZE];
1480
    int *dxy_buf = dxy_buf_stack;
1481
 
1482
    BOOL win_result = 0;
1483
    int i, j;
1484
 
1485
    cairo_solid_pattern_t *solid_pattern;
1486
    COLORREF color;
1487
 
1488
    cairo_matrix_t device_to_logical;
1489
 
1490
    int start_x, start_y;
1491
    double user_x, user_y;
1492
    int logical_x, logical_y;
1493
    unsigned int glyph_index_option;
1494
 
1495
    /* We can only handle win32 fonts */
1496
    if (cairo_scaled_font_get_type (scaled_font) != CAIRO_FONT_TYPE_WIN32)
1497
        return CAIRO_INT_STATUS_UNSUPPORTED;
1498
 
1499
    /* We can only handle opaque solid color sources */
1500
    if (!_cairo_pattern_is_opaque_solid(source))
1501
        return CAIRO_INT_STATUS_UNSUPPORTED;
1502
 
1503
    /* We can only handle operator SOURCE or OVER with the destination
1504
     * having no alpha */
1505
    if ((op != CAIRO_OPERATOR_SOURCE && op != CAIRO_OPERATOR_OVER) ||
1506
        (dst->format != CAIRO_FORMAT_RGB24))
1507
        return CAIRO_INT_STATUS_UNSUPPORTED;
1508
 
1509
    /* If we have a fallback mask clip set on the dst, we have
1510
     * to go through the fallback path, but only if we're not
1511
     * doing this for printing */
1512
    if (clip != NULL) {
1513
        if ((dst->flags & CAIRO_WIN32_SURFACE_FOR_PRINTING) == 0) {
1514
            cairo_region_t *clip_region;
1515
            cairo_status_t status;
1516
 
1517
            status = _cairo_clip_get_region (clip, &clip_region);
1518
            assert (status != CAIRO_INT_STATUS_NOTHING_TO_DO);
1519
            if (status)
1520
                return status;
1521
 
1522
            _cairo_win32_surface_set_clip_region (surface, clip_region);
1523
        }
1524
    }
1525
 
1526
    solid_pattern = (cairo_solid_pattern_t *)source;
1527
    color = RGB(((int)solid_pattern->color.red_short) >> 8,
1528
                ((int)solid_pattern->color.green_short) >> 8,
1529
                ((int)solid_pattern->color.blue_short) >> 8);
1530
 
1531
    cairo_win32_scaled_font_get_device_to_logical(scaled_font, &device_to_logical);
1532
 
1533
    SaveDC(dst->dc);
1534
 
1535
    cairo_win32_scaled_font_select_font(scaled_font, dst->dc);
1536
    SetTextColor(dst->dc, color);
1537
    SetTextAlign(dst->dc, TA_BASELINE | TA_LEFT);
1538
    SetBkMode(dst->dc, TRANSPARENT);
1539
 
1540
    if (num_glyphs > STACK_GLYPH_SIZE) {
1541
        glyph_buf = (WORD *) _cairo_malloc_ab (num_glyphs, sizeof(WORD));
1542
        dxy_buf = (int *) _cairo_malloc_abc (num_glyphs, sizeof(int), 2);
1543
    }
1544
 
1545
    /* It is vital that dx values for dxy_buf are calculated from the delta of
1546
     * _logical_ x coordinates (not user x coordinates) or else the sum of all
1547
     * previous dx values may start to diverge from the current glyph's x
1548
     * coordinate due to accumulated rounding error. As a result strings could
1549
     * be painted shorter or longer than expected. */
1550
 
1551
    user_x = glyphs[0].x;
1552
    user_y = glyphs[0].y;
1553
 
1554
    cairo_matrix_transform_point(&device_to_logical,
1555
                                 &user_x, &user_y);
1556
 
1557
    logical_x = _cairo_lround (user_x);
1558
    logical_y = _cairo_lround (user_y);
1559
 
1560
    start_x = logical_x;
1561
    start_y = logical_y;
1562
 
1563
    for (i = 0, j = 0; i < num_glyphs; ++i, j = 2 * i) {
1564
        glyph_buf[i] = (WORD) glyphs[i].index;
1565
        if (i == num_glyphs - 1) {
1566
            dxy_buf[j] = 0;
1567
            dxy_buf[j+1] = 0;
1568
        } else {
1569
            double next_user_x = glyphs[i+1].x;
1570
            double next_user_y = glyphs[i+1].y;
1571
            int next_logical_x, next_logical_y;
1572
 
1573
            cairo_matrix_transform_point(&device_to_logical,
1574
                                         &next_user_x, &next_user_y);
1575
 
1576
            next_logical_x = _cairo_lround (next_user_x);
1577
            next_logical_y = _cairo_lround (next_user_y);
1578
 
1579
            dxy_buf[j] = _cairo_lround (next_logical_x - logical_x);
1580
            dxy_buf[j+1] = _cairo_lround (next_logical_y - logical_y);
1581
 
1582
            logical_x = next_logical_x;
1583
            logical_y = next_logical_y;
1584
        }
1585
    }
1586
 
1587
    /* Using glyph indices for a Type 1 font does not work on a
1588
     * printer DC. The win32 printing surface will convert the the
1589
     * glyph indices of Type 1 fonts to the unicode values.
1590
     */
1591
    if ((dst->flags & CAIRO_WIN32_SURFACE_FOR_PRINTING) &&
1592
        _cairo_win32_scaled_font_is_type1 (scaled_font))
1593
    {
1594
        glyph_index_option = 0;
1595
    }
1596
    else
1597
    {
1598
        glyph_index_option = ETO_GLYPH_INDEX;
1599
    }
1600
 
1601
    win_result = ExtTextOutW(dst->dc,
1602
                             start_x,
1603
                             start_y,
1604
                             glyph_index_option | ETO_PDY,
1605
                             NULL,
1606
                             glyph_buf,
1607
                             num_glyphs,
1608
                             dxy_buf);
1609
    if (!win_result) {
1610
        _cairo_win32_print_gdi_error("_cairo_win32_surface_show_glyphs(ExtTextOutW failed)");
1611
    }
1612
 
1613
    RestoreDC(dst->dc, -1);
1614
 
1615
    if (glyph_buf != glyph_buf_stack) {
1616
        free(glyph_buf);
1617
        free(dxy_buf);
1618
    }
1619
    return (win_result) ? CAIRO_STATUS_SUCCESS : CAIRO_INT_STATUS_UNSUPPORTED;
1620
#else
1621
    return CAIRO_INT_STATUS_UNSUPPORTED;
1622
#endif
1623
}
1624
 
1625
#undef STACK_GLYPH_SIZE
1626
 
1627
/**
1628
 * cairo_win32_surface_create:
1629
 * @hdc: the DC to create a surface for
1630
 *
1631
 * Creates a cairo surface that targets the given DC.  The DC will be
1632
 * queried for its initial clip extents, and this will be used as the
1633
 * size of the cairo surface.  The resulting surface will always be of
1634
 * format %CAIRO_FORMAT_RGB24; should you need another surface format,
1635
 * you will need to create one through
1636
 * cairo_win32_surface_create_with_dib().
1637
 *
1638
 * Return value: the newly created surface
1639
 **/
1640
cairo_surface_t *
1641
cairo_win32_surface_create (HDC hdc)
1642
{
1643
    cairo_win32_surface_t *surface;
1644
 
1645
    cairo_format_t format;
1646
    RECT rect;
1647
 
1648
    /* Assume that everything coming in as a HDC is RGB24 */
1649
    format = CAIRO_FORMAT_RGB24;
1650
 
1651
    surface = malloc (sizeof (cairo_win32_surface_t));
1652
    if (surface == NULL)
1653
        return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
1654
 
1655
    if (_cairo_win32_save_initial_clip (hdc, surface) != CAIRO_STATUS_SUCCESS) {
1656
        free (surface);
1657
        return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
1658
    }
1659
 
1660
    surface->clip_region = NULL;
1661
    surface->image = NULL;
1662
    surface->format = format;
1663
 
1664
    surface->dc = hdc;
1665
    surface->bitmap = NULL;
1666
    surface->is_dib = FALSE;
1667
    surface->saved_dc_bitmap = NULL;
1668
    surface->brush = NULL;
1669
    surface->old_brush = NULL;
1670
    surface->font_subsets = NULL;
1671
 
1672
    GetClipBox(hdc, &rect);
1673
    surface->extents.x = rect.left;
1674
    surface->extents.y = rect.top;
1675
    surface->extents.width = rect.right - rect.left;
1676
    surface->extents.height = rect.bottom - rect.top;
1677
 
1678
    surface->flags = _cairo_win32_flags_for_dc (surface->dc);
1679
 
1680
    _cairo_surface_init (&surface->base, &cairo_win32_surface_backend,
1681
                         _cairo_content_from_format (format));
1682
 
1683
    return (cairo_surface_t *)surface;
1684
}
1685
 
1686
/**
1687
 * cairo_win32_surface_create_with_dib:
1688
 * @format: format of pixels in the surface to create
1689
 * @width: width of the surface, in pixels
1690
 * @height: height of the surface, in pixels
1691
 *
1692
 * Creates a device-independent-bitmap surface not associated with
1693
 * any particular existing surface or device context. The created
1694
 * bitmap will be uninitialized.
1695
 *
1696
 * Return value: the newly created surface
1697
 *
1698
 * Since: 1.2
1699
 **/
1700
cairo_surface_t *
1701
cairo_win32_surface_create_with_dib (cairo_format_t format,
1702
                                     int            width,
1703
                                     int            height)
1704
{
1705
    return _cairo_win32_surface_create_for_dc (NULL, format, width, height);
1706
}
1707
 
1708
/**
1709
 * cairo_win32_surface_create_with_ddb:
1710
 * @hdc: the DC to create a surface for
1711
 * @format: format of pixels in the surface to create
1712
 * @width: width of the surface, in pixels
1713
 * @height: height of the surface, in pixels
1714
 *
1715
 * Creates a device-independent-bitmap surface not associated with
1716
 * any particular existing surface or device context. The created
1717
 * bitmap will be uninitialized.
1718
 *
1719
 * Return value: the newly created surface
1720
 *
1721
 * Since: 1.4
1722
 **/
1723
cairo_surface_t *
1724
cairo_win32_surface_create_with_ddb (HDC hdc,
1725
                                     cairo_format_t format,
1726
                                     int width,
1727
                                     int height)
1728
{
1729
    cairo_win32_surface_t *new_surf;
1730
    HBITMAP ddb;
1731
    HDC screen_dc, ddb_dc;
1732
    HBITMAP saved_dc_bitmap;
1733
 
1734
    if (format != CAIRO_FORMAT_RGB24)
1735
        return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_FORMAT));
1736
/* XXX handle these eventually
1737
        format != CAIRO_FORMAT_A8 ||
1738
        format != CAIRO_FORMAT_A1)
1739
*/
1740
 
1741
    if (!hdc) {
1742
        screen_dc = GetDC (NULL);
1743
        hdc = screen_dc;
1744
    } else {
1745
        screen_dc = NULL;
1746
    }
1747
 
1748
    ddb_dc = CreateCompatibleDC (hdc);
1749
    if (ddb_dc == NULL) {
1750
        new_surf = (cairo_win32_surface_t*) _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
1751
        goto FINISH;
1752
    }
1753
 
1754
    ddb = CreateCompatibleBitmap (hdc, width, height);
1755
    if (ddb == NULL) {
1756
        DeleteDC (ddb_dc);
1757
 
1758
        /* Note that if an app actually does hit this out of memory
1759
         * condition, it's going to have lots of other issues, as
1760
         * video memory is probably exhausted.  However, it can often
1761
         * continue using DIBs instead of DDBs.
1762
         */
1763
        new_surf = (cairo_win32_surface_t*) _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
1764
        goto FINISH;
1765
    }
1766
 
1767
    saved_dc_bitmap = SelectObject (ddb_dc, ddb);
1768
 
1769
    new_surf = (cairo_win32_surface_t*) cairo_win32_surface_create (ddb_dc);
1770
    new_surf->bitmap = ddb;
1771
    new_surf->saved_dc_bitmap = saved_dc_bitmap;
1772
    new_surf->is_dib = FALSE;
1773
 
1774
FINISH:
1775
    if (screen_dc)
1776
        ReleaseDC (NULL, screen_dc);
1777
 
1778
    return (cairo_surface_t*) new_surf;
1779
}
1780
 
1781
/**
1782
 * _cairo_surface_is_win32:
1783
 * @surface: a #cairo_surface_t
1784
 *
1785
 * Checks if a surface is a win32 surface.  This will
1786
 * return False if this is a win32 printing surface; use
1787
 * _cairo_surface_is_win32_printing() to check for that.
1788
 *
1789
 * Return value: True if the surface is an win32 surface
1790
 **/
1791
int
1792
_cairo_surface_is_win32 (cairo_surface_t *surface)
1793
{
1794
    return surface->backend == &cairo_win32_surface_backend;
1795
}
1796
 
1797
/**
1798
 * cairo_win32_surface_get_dc
1799
 * @surface: a #cairo_surface_t
1800
 *
1801
 * Returns the HDC associated with this surface, or %NULL if none.
1802
 * Also returns %NULL if the surface is not a win32 surface.
1803
 *
1804
 * Return value: HDC or %NULL if no HDC available.
1805
 *
1806
 * Since: 1.2
1807
 **/
1808
HDC
1809
cairo_win32_surface_get_dc (cairo_surface_t *surface)
1810
{
1811
    cairo_win32_surface_t *winsurf;
1812
 
1813
    if (_cairo_surface_is_win32 (surface)){
1814
        winsurf = (cairo_win32_surface_t *) surface;
1815
 
1816
        return winsurf->dc;
1817
    }
1818
 
1819
    if (_cairo_surface_is_paginated (surface)) {
1820
        cairo_surface_t *target;
1821
 
1822
        target = _cairo_paginated_surface_get_target (surface);
1823
 
1824
        if (_cairo_surface_is_win32_printing (target)) {
1825
            winsurf = (cairo_win32_surface_t *) target;
1826
 
1827
            return winsurf->dc;
1828
        }
1829
    }
1830
 
1831
    return NULL;
1832
}
1833
 
1834
/**
1835
 * cairo_win32_surface_get_image
1836
 * @surface: a #cairo_surface_t
1837
 *
1838
 * Returns a #cairo_surface_t image surface that refers to the same bits
1839
 * as the DIB of the Win32 surface.  If the passed-in win32 surface
1840
 * is not a DIB surface, %NULL is returned.
1841
 *
1842
 * Return value: a #cairo_surface_t (owned by the win32 #cairo_surface_t),
1843
 * or %NULL if the win32 surface is not a DIB.
1844
 *
1845
 * Since: 1.4
1846
 */
1847
cairo_surface_t *
1848
cairo_win32_surface_get_image (cairo_surface_t *surface)
1849
{
1850
    if (!_cairo_surface_is_win32(surface))
1851
        return NULL;
1852
 
1853
    return ((cairo_win32_surface_t*)surface)->image;
1854
}
1855
 
1856
static cairo_bool_t
1857
_cairo_win32_surface_is_similar (void *surface_a,
1858
                                 void *surface_b,
1859
                                 cairo_content_t content)
1860
{
1861
    cairo_win32_surface_t *a = surface_a;
1862
    cairo_win32_surface_t *b = surface_b;
1863
 
1864
    return a->dc == b->dc;
1865
}
1866
 
1867
typedef struct _cairo_win32_surface_span_renderer {
1868
    cairo_span_renderer_t base;
1869
 
1870
    cairo_operator_t op;
1871
    const cairo_pattern_t *pattern;
1872
    cairo_antialias_t antialias;
1873
 
1874
    cairo_image_surface_t *mask;
1875
    cairo_win32_surface_t *dst;
1876
    cairo_region_t *clip_region;
1877
 
1878
    cairo_composite_rectangles_t composite_rectangles;
1879
} cairo_win32_surface_span_renderer_t;
1880
 
1881
static cairo_status_t
1882
_cairo_win32_surface_span_renderer_render_row (
1883
    void                                *abstract_renderer,
1884
    int                                  y,
1885
    const cairo_half_open_span_t        *spans,
1886
    unsigned                             num_spans)
1887
{
1888
    cairo_win32_surface_span_renderer_t *renderer = abstract_renderer;
1889
    _cairo_image_surface_span_render_row (y, spans, num_spans, renderer->mask, &renderer->composite_rectangles);
1890
    return CAIRO_STATUS_SUCCESS;
1891
}
1892
 
1893
static void
1894
_cairo_win32_surface_span_renderer_destroy (void *abstract_renderer)
1895
{
1896
    cairo_win32_surface_span_renderer_t *renderer = abstract_renderer;
1897
    if (!renderer) return;
1898
 
1899
    if (renderer->mask != NULL)
1900
        cairo_surface_destroy (&renderer->mask->base);
1901
 
1902
    free (renderer);
1903
}
1904
 
1905
static cairo_status_t
1906
_cairo_win32_surface_span_renderer_finish (void *abstract_renderer)
1907
{
1908
    cairo_win32_surface_span_renderer_t *renderer = abstract_renderer;
1909
    cairo_status_t status = CAIRO_STATUS_SUCCESS;
1910
 
1911
    if (renderer->pattern == NULL || renderer->mask == NULL)
1912
        return CAIRO_STATUS_SUCCESS;
1913
 
1914
    status = cairo_surface_status (&renderer->mask->base);
1915
    if (status == CAIRO_STATUS_SUCCESS) {
1916
        cairo_composite_rectangles_t *rects = &renderer->composite_rectangles;
1917
        cairo_win32_surface_t *dst = renderer->dst;
1918
        cairo_pattern_t *mask_pattern = cairo_pattern_create_for_surface (&renderer->mask->base);
1919
        /* composite onto the image surface directly if we can */
1920
        if (dst->image) {
1921
            GdiFlush(); /* XXX: I'm not sure if this needed or not */
1922
 
1923
            status = dst->image->backend->composite (renderer->op,
1924
                    renderer->pattern, mask_pattern, dst->image,
1925
                    rects->src.x,
1926
                    rects->src.y,
1927
                    0, 0,               /* mask.x, mask.y */
1928
                    rects->dst.x, rects->dst.y,
1929
                    rects->width, rects->height,
1930
                    renderer->clip_region);
1931
        } else {
1932
            /* otherwise go through the fallback_composite path which
1933
             * will do the appropriate surface acquisition */
1934
            status = _cairo_surface_fallback_composite (
1935
                    renderer->op,
1936
                    renderer->pattern, mask_pattern, &dst->base,
1937
                    rects->src.x,
1938
                    rects->src.y,
1939
                    0, 0,               /* mask.x, mask.y */
1940
                    rects->dst.x, rects->dst.y,
1941
                    rects->width, rects->height,
1942
                    renderer->clip_region);
1943
        }
1944
        cairo_pattern_destroy (mask_pattern);
1945
 
1946
    }
1947
    if (status != CAIRO_STATUS_SUCCESS)
1948
        return _cairo_span_renderer_set_error (abstract_renderer,
1949
                                               status);
1950
    return CAIRO_STATUS_SUCCESS;
1951
}
1952
 
1953
static cairo_bool_t
1954
_cairo_win32_surface_check_span_renderer (cairo_operator_t        op,
1955
                                          const cairo_pattern_t  *pattern,
1956
                                          void                   *abstract_dst,
1957
                                          cairo_antialias_t       antialias)
1958
{
1959
    (void) op;
1960
    (void) pattern;
1961
    (void) abstract_dst;
1962
    (void) antialias;
1963
    return TRUE;
1964
}
1965
 
1966
static cairo_span_renderer_t *
1967
_cairo_win32_surface_create_span_renderer (cairo_operator_t      op,
1968
                                           const cairo_pattern_t  *pattern,
1969
                                           void                 *abstract_dst,
1970
                                           cairo_antialias_t     antialias,
1971
                                           const cairo_composite_rectangles_t *rects,
1972
                                           cairo_region_t       *clip_region)
1973
{
1974
    cairo_win32_surface_t *dst = abstract_dst;
1975
    cairo_win32_surface_span_renderer_t *renderer;
1976
    cairo_status_t status;
1977
    int width = rects->width;
1978
    int height = rects->height;
1979
 
1980
    renderer = calloc(1, sizeof(*renderer));
1981
    if (renderer == NULL)
1982
        return _cairo_span_renderer_create_in_error (CAIRO_STATUS_NO_MEMORY);
1983
 
1984
    renderer->base.destroy = _cairo_win32_surface_span_renderer_destroy;
1985
    renderer->base.finish = _cairo_win32_surface_span_renderer_finish;
1986
    renderer->base.render_row =
1987
        _cairo_win32_surface_span_renderer_render_row;
1988
    renderer->op = op;
1989
    renderer->pattern = pattern;
1990
    renderer->antialias = antialias;
1991
    renderer->dst = dst;
1992
    renderer->clip_region = clip_region;
1993
 
1994
    renderer->composite_rectangles = *rects;
1995
 
1996
    /* TODO: support rendering to A1 surfaces (or: go add span
1997
     * compositing to pixman.) */
1998
    renderer->mask = (cairo_image_surface_t *)
1999
        cairo_image_surface_create (CAIRO_FORMAT_A8,
2000
                                    width, height);
2001
 
2002
    status = cairo_surface_status (&renderer->mask->base);
2003
 
2004
    if (status != CAIRO_STATUS_SUCCESS) {
2005
        _cairo_win32_surface_span_renderer_destroy (renderer);
2006
        return _cairo_span_renderer_create_in_error (status);
2007
    }
2008
    return &renderer->base;
2009
}
2010
 
2011
 
2012
static const cairo_surface_backend_t cairo_win32_surface_backend = {
2013
    CAIRO_SURFACE_TYPE_WIN32,
2014
    _cairo_win32_surface_create_similar,
2015
    _cairo_win32_surface_finish,
2016
    _cairo_win32_surface_acquire_source_image,
2017
    _cairo_win32_surface_release_source_image,
2018
    _cairo_win32_surface_acquire_dest_image,
2019
    _cairo_win32_surface_release_dest_image,
2020
    NULL, /* clone similar */
2021
    _cairo_win32_surface_composite,
2022
    _cairo_win32_surface_fill_rectangles,
2023
    NULL, /* composite_trapezoids */
2024
    _cairo_win32_surface_create_span_renderer,
2025
    _cairo_win32_surface_check_span_renderer,
2026
    NULL, /* copy_page */
2027
    NULL, /* show_page */
2028
    _cairo_win32_surface_get_extents,
2029
    NULL, /* old_show_glyphs */
2030
    NULL, /* get_font_options */
2031
    _cairo_win32_surface_flush,
2032
    NULL, /* mark_dirty_rectangle */
2033
    NULL, /* scaled_font_fini */
2034
    NULL, /* scaled_glyph_fini */
2035
 
2036
    NULL, /* paint */
2037
    NULL, /* mask */
2038
    NULL, /* stroke */
2039
    NULL, /* fill */
2040
    _cairo_win32_surface_show_glyphs,
2041
 
2042
    NULL,  /* snapshot */
2043
    _cairo_win32_surface_is_similar,
2044
};
2045
 
2046
/* Notes:
2047
 *
2048
 * Win32 alpha-understanding functions
2049
 *
2050
 * BitBlt - will copy full 32 bits from a 32bpp DIB to result
2051
 *          (so it's safe to use for ARGB32->ARGB32 SOURCE blits)
2052
 *          (but not safe going RGB24->ARGB32, if RGB24 is also represented
2053
 *           as a 32bpp DIB, since the alpha isn't discarded!)
2054
 *
2055
 * AlphaBlend - if both the source and dest have alpha, even if AC_SRC_ALPHA isn't set,
2056
 *              it will still copy over the src alpha, because the SCA value (255) will be
2057
 *              multiplied by all the src components.
2058
 */
2059
 
2060
 
2061
cairo_int_status_t
2062
_cairo_win32_save_initial_clip (HDC hdc, cairo_win32_surface_t *surface)
2063
{
2064
    RECT rect;
2065
    int clipBoxType;
2066
    int gm;
2067
    XFORM saved_xform;
2068
 
2069
    /* GetClipBox/GetClipRgn and friends interact badly with a world transform
2070
     * set.  GetClipBox returns values in logical (transformed) coordinates;
2071
     * it's unclear what GetClipRgn returns, because the region is empty in the
2072
     * case of a SIMPLEREGION clip, but I assume device (untransformed) coordinates.
2073
     * Similarily, IntersectClipRect works in logical units, whereas SelectClipRgn
2074
     * works in device units.
2075
     *
2076
     * So, avoid the whole mess and get rid of the world transform
2077
     * while we store our initial data and when we restore initial coordinates.
2078
     *
2079
     * XXX we may need to modify x/y by the ViewportOrg or WindowOrg
2080
     * here in GM_COMPATIBLE; unclear.
2081
     */
2082
    gm = GetGraphicsMode (hdc);
2083
    if (gm == GM_ADVANCED) {
2084
        GetWorldTransform (hdc, &saved_xform);
2085
        ModifyWorldTransform (hdc, NULL, MWT_IDENTITY);
2086
    }
2087
 
2088
    clipBoxType = GetClipBox (hdc, &rect);
2089
    if (clipBoxType == ERROR) {
2090
        _cairo_win32_print_gdi_error ("cairo_win32_surface_create");
2091
        SetGraphicsMode (hdc, gm);
2092
        /* XXX: Can we make a more reasonable guess at the error cause here? */
2093
        return _cairo_error (CAIRO_STATUS_NO_MEMORY);
2094
    }
2095
 
2096
    surface->clip_rect.x = rect.left;
2097
    surface->clip_rect.y = rect.top;
2098
    surface->clip_rect.width = rect.right - rect.left;
2099
    surface->clip_rect.height = rect.bottom - rect.top;
2100
 
2101
    surface->initial_clip_rgn = NULL;
2102
    surface->had_simple_clip = FALSE;
2103
 
2104
    if (clipBoxType == COMPLEXREGION) {
2105
        surface->initial_clip_rgn = CreateRectRgn (0, 0, 0, 0);
2106
        if (GetClipRgn (hdc, surface->initial_clip_rgn) <= 0) {
2107
            DeleteObject(surface->initial_clip_rgn);
2108
            surface->initial_clip_rgn = NULL;
2109
        }
2110
    } else if (clipBoxType == SIMPLEREGION) {
2111
        surface->had_simple_clip = TRUE;
2112
    }
2113
 
2114
    if (gm == GM_ADVANCED)
2115
        SetWorldTransform (hdc, &saved_xform);
2116
 
2117
    return CAIRO_STATUS_SUCCESS;
2118
}
2119
 
2120
cairo_int_status_t
2121
_cairo_win32_restore_initial_clip (cairo_win32_surface_t *surface)
2122
{
2123
    cairo_int_status_t status = CAIRO_STATUS_SUCCESS;
2124
 
2125
    XFORM saved_xform;
2126
    int gm = GetGraphicsMode (surface->dc);
2127
    if (gm == GM_ADVANCED) {
2128
        GetWorldTransform (surface->dc, &saved_xform);
2129
        ModifyWorldTransform (surface->dc, NULL, MWT_IDENTITY);
2130
    }
2131
 
2132
    /* initial_clip_rgn will either be a real region or NULL (which means reset to no clip region) */
2133
    SelectClipRgn (surface->dc, surface->initial_clip_rgn);
2134
 
2135
    if (surface->had_simple_clip) {
2136
        /* then if we had a simple clip, intersect */
2137
        IntersectClipRect (surface->dc,
2138
                           surface->clip_rect.x,
2139
                           surface->clip_rect.y,
2140
                           surface->clip_rect.x + surface->clip_rect.width,
2141
                           surface->clip_rect.y + surface->clip_rect.height);
2142
    }
2143
 
2144
    if (gm == GM_ADVANCED)
2145
        SetWorldTransform (surface->dc, &saved_xform);
2146
 
2147
    return status;
2148
}
2149
 
2150
void
2151
_cairo_win32_debug_dump_hrgn (HRGN rgn, char *header)
2152
{
2153
    RGNDATA *rd;
2154
    unsigned int z;
2155
 
2156
    if (header)
2157
        fprintf (stderr, "%s\n", header);
2158
 
2159
    if (rgn == NULL) {
2160
        fprintf (stderr, " NULL\n");
2161
    }
2162
 
2163
    z = GetRegionData(rgn, 0, NULL);
2164
    rd = (RGNDATA*) malloc(z);
2165
    z = GetRegionData(rgn, z, rd);
2166
 
2167
    fprintf (stderr, " %ld rects, bounds: %ld %ld %ld %ld\n",
2168
             rd->rdh.nCount,
2169
             rd->rdh.rcBound.left,
2170
             rd->rdh.rcBound.top,
2171
             rd->rdh.rcBound.right - rd->rdh.rcBound.left,
2172
             rd->rdh.rcBound.bottom - rd->rdh.rcBound.top);
2173
 
2174
    for (z = 0; z < rd->rdh.nCount; z++) {
2175
        RECT r = ((RECT*)rd->Buffer)[z];
2176
        fprintf (stderr, " [%d]: [%ld %ld %ld %ld]\n",
2177
                 z, r.left, r.top, r.right - r.left, r.bottom - r.top);
2178
    }
2179
 
2180
    free(rd);
2181
    fflush (stderr);
2182
}