1
2/*
3 * Copyright 2012 The Android Open Source Project
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8
9/**
10 * Functions to transform scanlines between packed-pixel formats.
11 */
12
13#include "SkBitmap.h"
14#include "SkColor.h"
15#include "SkColorPriv.h"
16#include "SkPreConfig.h"
17#include "SkUnPreMultiply.h"
18
19/**
20 * Function template for transforming scanlines.
21 * Transform 'width' pixels from 'src' buffer into 'dst' buffer,
22 * repacking color channel data as appropriate for the given transformation.
23 */
24typedef void (*transform_scanline_proc)(const char* SK_RESTRICT src,
25                                        int width, char* SK_RESTRICT dst);
26
27/**
28 * Identity transformation: just copy bytes from src to dst.
29 */
30static void transform_scanline_memcpy(const char* SK_RESTRICT src, int width,
31                                      char* SK_RESTRICT dst) {
32    memcpy(dst, src, width);
33}
34
35/**
36 * Transform from kRGB_565_Config to 3-bytes-per-pixel RGB.
37 * Alpha channel data is not present in kRGB_565_Config format, so there is no
38 * alpha channel data to preserve.
39 */
40static void transform_scanline_565(const char* SK_RESTRICT src, int width,
41                                   char* SK_RESTRICT dst) {
42    const uint16_t* SK_RESTRICT srcP = (const uint16_t*)src;
43    for (int i = 0; i < width; i++) {
44        unsigned c = *srcP++;
45        *dst++ = SkPacked16ToR32(c);
46        *dst++ = SkPacked16ToG32(c);
47        *dst++ = SkPacked16ToB32(c);
48    }
49}
50
51/**
52 * Transform from kARGB_8888_Config to 3-bytes-per-pixel RGB.
53 * Alpha channel data, if any, is abandoned.
54 */
55static void transform_scanline_888(const char* SK_RESTRICT src, int width,
56                                   char* SK_RESTRICT dst) {
57    const SkPMColor* SK_RESTRICT srcP = (const SkPMColor*)src;
58    for (int i = 0; i < width; i++) {
59        SkPMColor c = *srcP++;
60        *dst++ = SkGetPackedR32(c);
61        *dst++ = SkGetPackedG32(c);
62        *dst++ = SkGetPackedB32(c);
63    }
64}
65
66/**
67 * Transform from kARGB_4444_Config to 3-bytes-per-pixel RGB.
68 * Alpha channel data, if any, is abandoned.
69 */
70static void transform_scanline_444(const char* SK_RESTRICT src, int width,
71                                   char* SK_RESTRICT dst) {
72    const SkPMColor16* SK_RESTRICT srcP = (const SkPMColor16*)src;
73    for (int i = 0; i < width; i++) {
74        SkPMColor16 c = *srcP++;
75        *dst++ = SkPacked4444ToR32(c);
76        *dst++ = SkPacked4444ToG32(c);
77        *dst++ = SkPacked4444ToB32(c);
78    }
79}
80
81/**
82 * Transform from kARGB_8888_Config to 4-bytes-per-pixel RGBA.
83 * (This would be the identity transformation, except for byte-order and
84 * scaling of RGB based on alpha channel).
85 */
86static void transform_scanline_8888(const char* SK_RESTRICT src, int width,
87                                    char* SK_RESTRICT dst) {
88    const SkPMColor* SK_RESTRICT srcP = (const SkPMColor*)src;
89    const SkUnPreMultiply::Scale* SK_RESTRICT table =
90                                              SkUnPreMultiply::GetScaleTable();
91
92    for (int i = 0; i < width; i++) {
93        SkPMColor c = *srcP++;
94        unsigned a = SkGetPackedA32(c);
95        unsigned r = SkGetPackedR32(c);
96        unsigned g = SkGetPackedG32(c);
97        unsigned b = SkGetPackedB32(c);
98
99        if (0 != a && 255 != a) {
100            SkUnPreMultiply::Scale scale = table[a];
101            r = SkUnPreMultiply::ApplyScale(scale, r);
102            g = SkUnPreMultiply::ApplyScale(scale, g);
103            b = SkUnPreMultiply::ApplyScale(scale, b);
104        }
105        *dst++ = r;
106        *dst++ = g;
107        *dst++ = b;
108        *dst++ = a;
109    }
110}
111
112/**
113 * Transform from kARGB_8888_Config to 4-bytes-per-pixel RGBA,
114 * with scaling of RGB based on alpha channel.
115 */
116static void transform_scanline_4444(const char* SK_RESTRICT src, int width,
117                                    char* SK_RESTRICT dst) {
118    const SkPMColor16* SK_RESTRICT srcP = (const SkPMColor16*)src;
119    const SkUnPreMultiply::Scale* SK_RESTRICT table =
120                                              SkUnPreMultiply::GetScaleTable();
121
122    for (int i = 0; i < width; i++) {
123        SkPMColor16 c = *srcP++;
124        unsigned a = SkPacked4444ToA32(c);
125        unsigned r = SkPacked4444ToR32(c);
126        unsigned g = SkPacked4444ToG32(c);
127        unsigned b = SkPacked4444ToB32(c);
128
129        if (0 != a && 255 != a) {
130            SkUnPreMultiply::Scale scale = table[a];
131            r = SkUnPreMultiply::ApplyScale(scale, r);
132            g = SkUnPreMultiply::ApplyScale(scale, g);
133            b = SkUnPreMultiply::ApplyScale(scale, b);
134        }
135        *dst++ = r;
136        *dst++ = g;
137        *dst++ = b;
138        *dst++ = a;
139    }
140}
141