1/*
2 * Copyright 2006 The Android Open Source Project
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8
9#include "include/core/SkBitmap.h"
10#include "src/core/SkMask.h"
11
12#ifndef ClearLow3Bits_DEFINED
13#define ClearLow3Bits_DEFINED
14    #define ClearLow3Bits(x)    ((unsigned)(x) >> 3 << 3)
15#endif
16
17/*
18    SK_BLITBWMASK_NAME          name of function(const SkBitmap& bitmap, const SkMask& mask, const SkIRect& clip, SK_BLITBWMASK_ARGS)
19    SK_BLITBWMASK_ARGS          list of additional arguments to SK_BLITBWMASK_NAME, beginning with a comma
20    SK_BLITBWMASK_BLIT8         name of function(U8CPU byteMask, SK_BLITBWMASK_DEVTYPE* dst, int x, int y)
21    SK_BLITBWMASK_GETADDR       either writable_addr[8,16,32]
22    SK_BLITBWMASK_DEVTYPE       either U32 or U16 or U8
23*/
24
25static void SK_BLITBWMASK_NAME(const SkPixmap& dstPixmap, const SkMask& srcMask,
26                               const SkIRect& clip SK_BLITBWMASK_ARGS) {
27    SkASSERT(clip.fRight <= srcMask.fBounds.fRight);
28
29    int cx = clip.fLeft;
30    int cy = clip.fTop;
31    int maskLeft = srcMask.fBounds.fLeft;
32    unsigned mask_rowBytes = srcMask.fRowBytes;
33    size_t bitmap_rowBytes = dstPixmap.rowBytes();
34    unsigned height = clip.height();
35
36    SkASSERT(mask_rowBytes != 0);
37    SkASSERT(bitmap_rowBytes != 0);
38    SkASSERT(height != 0);
39
40    const uint8_t* bits = srcMask.getAddr1(cx, cy);
41    SK_BLITBWMASK_DEVTYPE* device = dstPixmap.SK_BLITBWMASK_GETADDR(cx, cy);
42
43    if (cx == maskLeft && clip.fRight == srcMask.fBounds.fRight)
44    {
45        do {
46            SK_BLITBWMASK_DEVTYPE* dst = device;
47            unsigned rb = mask_rowBytes;
48            do {
49                U8CPU mask = *bits++;
50                SK_BLITBWMASK_BLIT8(mask, dst);
51                dst += 8;
52            } while (--rb != 0);
53            device = (SK_BLITBWMASK_DEVTYPE*)((char*)device + bitmap_rowBytes);
54        } while (--height != 0);
55    }
56    else
57    {
58        int left_edge = cx - maskLeft;
59        SkASSERT(left_edge >= 0);
60        int rite_edge = clip.fRight - maskLeft;
61        SkASSERT(rite_edge > left_edge);
62
63        int left_mask = 0xFF >> (left_edge & 7);
64        int rite_mask = 0xFF << (8 - (rite_edge & 7));
65        rite_mask &= 0xFF;  // only want low-8 bits of mask
66        int full_runs = (rite_edge >> 3) - ((left_edge + 7) >> 3);
67
68        // check for empty right mask, so we don't read off the end (or go slower than we need to)
69        if (rite_mask == 0)
70        {
71            SkASSERT(full_runs >= 0);
72            full_runs -= 1;
73            rite_mask = 0xFF;
74        }
75        if (left_mask == 0xFF)
76            full_runs -= 1;
77
78        // back up manually so we can keep in sync with our byte-aligned src
79        // and not trigger an assert from the getAddr## function
80        device -= left_edge & 7;
81
82        if (full_runs < 0)
83        {
84            left_mask &= rite_mask;
85            SkASSERT(left_mask != 0);
86            do {
87                U8CPU mask = *bits & left_mask;
88                SK_BLITBWMASK_BLIT8(mask, device);
89                bits += mask_rowBytes;
90                device = (SK_BLITBWMASK_DEVTYPE*)((char*)device + bitmap_rowBytes);
91            } while (--height != 0);
92        }
93        else
94        {
95            do {
96                int runs = full_runs;
97                SK_BLITBWMASK_DEVTYPE* dst = device;
98                const uint8_t* b = bits;
99                U8CPU   mask;
100
101                mask = *b++ & left_mask;
102                SK_BLITBWMASK_BLIT8(mask, dst);
103                dst += 8;
104
105                while (--runs >= 0)
106                {
107                    mask = *b++;
108                    SK_BLITBWMASK_BLIT8(mask, dst);
109                    dst += 8;
110                }
111
112                mask = *b & rite_mask;
113                SK_BLITBWMASK_BLIT8(mask, dst);
114
115                bits += mask_rowBytes;
116                device = (SK_BLITBWMASK_DEVTYPE*)((char*)device + bitmap_rowBytes);
117            } while (--height != 0);
118        }
119    }
120}
121
122#undef SK_BLITBWMASK_NAME
123#undef SK_BLITBWMASK_ARGS
124#undef SK_BLITBWMASK_BLIT8
125#undef SK_BLITBWMASK_GETADDR
126#undef SK_BLITBWMASK_DEVTYPE
127#undef SK_BLITBWMASK_DOROWSETUP
128