1/*
2 * Copyright © 1998 Keith Packard
3 * Copyright © 2012 Intel Corporation
4 *
5 * Permission to use, copy, modify, distribute, and sell this software and its
6 * documentation for any purpose is hereby granted without fee, provided that
7 * the above copyright notice appear in all copies and that both that
8 * copyright notice and this permission notice appear in supporting
9 * documentation, and that the name of Keith Packard not be used in
10 * advertising or publicity pertaining to distribution of the software without
11 * specific, written prior permission.  Keith Packard makes no
12 * representations about the suitability of this software for any purpose.  It
13 * is provided "as is" without express or implied warranty.
14 *
15 * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
16 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
17 * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
18 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
19 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
20 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
21 * PERFORMANCE OF THIS SOFTWARE.
22 */
23
24#include <string.h>
25
26#include "fb.h"
27#include "fbclip.h"
28
29struct fbPutZImage {
30	FbStip *src, *dst;
31	FbStride src_stride, dst_stride;
32
33	int dst_x, dst_y;
34	int x0, y0;
35};
36
37inline static void
38_fbPutZImage(DrawablePtr drawable, GCPtr gc, const BoxRec *b, void *_data)
39{
40	struct fbPutZImage *data = _data;
41	int bpp = drawable->bitsPerPixel;
42
43	fbBltStip(data->src + (b->y1 - data->y0) * data->src_stride, data->src_stride,
44		  (b->x1 - data->x0) * bpp,
45		  data->dst + (b->y1 + data->dst_y) * data->dst_stride,
46		  data->dst_stride,
47		  (b->x1 + data->dst_x) * bpp,
48		  (b->x2 - b->x1) * bpp, (b->y2 - b->y1),
49		  gc->alu, fb_gc(gc)->pm, bpp);
50}
51
52static void
53fbPutZImage(DrawablePtr drawable, GCPtr gc,
54            int x, int y, int width, int height,
55	    FbStip *src, FbStride srcStride)
56{
57	PixmapPtr pixmap;
58	struct fbPutZImage data;
59	BoxRec box;
60
61	box.x1 = data.x0 = x;
62	box.y1 = data.y0 = y;
63	box.x2 = x + width;
64	box.y2 = y + height;
65	data.src = src;
66	data.src_stride = srcStride;
67
68	fbGetDrawablePixmap(drawable, pixmap, data.dst_x, data.dst_y);
69	data.dst = pixmap->devPrivate.ptr;
70	data.dst_stride = pixmap->devKind / sizeof(FbStip);
71
72	fbDrawableRun(drawable, gc, &box, _fbPutZImage, &data);
73}
74
75struct fbPutXYImage {
76	FbStip *src, *dst;
77	FbStride src_stride, dst_stride;
78
79	int dst_x, dst_y, src_x;
80	int x0, y0;
81
82	int alu, pm;
83	FbBits fgand, fgxor, bgand, bgxor;
84};
85
86inline static void
87_fbPutXYImage1(DrawablePtr drawable, GCPtr gc, const BoxRec *b, void *_data)
88{
89	struct fbPutXYImage *data = _data;
90	int bpp = drawable->bitsPerPixel;
91
92	fbBltStip(data->src + (b->y1 - data->y0) * data->src_stride, data->src_stride,
93		  (b->x1 - data->x0) + data->src_x,
94		  (FbStip *) (data->dst + (b->y1 + data->dst_y) * data->dst_stride),
95		  data->dst_stride,
96		  (b->x1 + data->dst_x) * bpp,
97		  (b->x2 - b->x1) * bpp, (b->y2 - b->y1),
98		  data->alu, data->pm, bpp);
99}
100
101inline static void
102_fbPutXYImageN(DrawablePtr drawable, GCPtr gc, const BoxRec *b, void *_data)
103{
104	struct fbPutXYImage *data = _data;
105	int bpp = drawable->bitsPerPixel;
106
107	fbBltOne(data->src + (b->y1 - data->y0) * data->src_stride,
108		 data->src_stride,
109		 (b->x1 - data->x0) + data->src_x,
110		 data->dst + (b->y1 + data->dst_y) * data->dst_stride,
111		 data->dst_stride,
112		 (b->x1 + data->dst_x) * bpp, bpp,
113		 (b->x2 - b->x1) * bpp, (b->y2 - b->y1),
114		 data->fgand, data->fgxor,
115		 data->bgand, data->bgxor);
116}
117
118void
119fbPutXYImage(DrawablePtr drawable, GCPtr gc,
120             FbBits fg, FbBits bg, FbBits pm, int alu, Bool opaque,
121             int x, int y, int width, int height,
122	     FbStip *src, FbStride srcStride, int srcX)
123{
124	PixmapPtr pixmap;
125	struct fbPutXYImage data;
126	BoxRec box;
127
128	box.x1 = data.x0 = x;
129	box.y1 = data.y0 = y;
130	box.x2 = x + width;
131	box.y2 = y + height;
132	data.src = src;
133	data.src_stride = srcStride;
134	data.src_x = srcX;
135
136	fbGetDrawablePixmap(drawable, pixmap, data.dst_x, data.dst_y);
137	data.dst = pixmap->devPrivate.ptr;
138	data.dst_stride = pixmap->devKind / sizeof(FbStip);
139
140	if (drawable->bitsPerPixel == 1) {
141		if (opaque)
142			data.alu = FbOpaqueStipple1Rop(alu, fg, bg);
143		else
144			data.alu = FbStipple1Rop(alu, fg);
145		data.pm = pm;
146
147		fbDrawableRun(drawable, gc, &box, _fbPutXYImage1, &data);
148	} else {
149		data.fgand = fbAnd(alu, fg, pm);
150		data.fgxor = fbXor(alu, fg, pm);
151		if (opaque) {
152			data.bgand = fbAnd(alu, bg, pm);
153			data.bgxor = fbXor(alu, bg, pm);
154		} else {
155			data.bgand = fbAnd(GXnoop, (FbBits) 0, FB_ALLONES);
156			data.bgxor = fbXor(GXnoop, (FbBits) 0, FB_ALLONES);
157		}
158
159		fbDrawableRun(drawable, gc, &box, _fbPutXYImageN, &data);
160	}
161}
162
163void
164fbPutImage(DrawablePtr drawable, GCPtr gc, int depth,
165           int x, int y, int w, int h,
166	   int leftPad, int format, char *image)
167{
168	FbGCPrivPtr pgc = fb_gc(gc);
169	unsigned long i;
170	FbStride srcStride;
171	FbStip *src = (FbStip *)image;
172
173	DBG(("%s (%d, %d)x(%d, %d)\n", __FUNCTION__, x, y, w, h));
174
175	x += drawable->x;
176	y += drawable->y;
177
178	switch (format) {
179	case XYBitmap:
180		srcStride = BitmapBytePad(w + leftPad) / sizeof(FbStip);
181		fbPutXYImage(drawable, gc,
182			     pgc->fg, pgc->bg, pgc->pm,
183			     gc->alu, TRUE,
184			     x, y, w, h,
185			     src, srcStride, leftPad);
186		break;
187	case XYPixmap:
188		srcStride = BitmapBytePad(w + leftPad) / sizeof(FbStip);
189		for (i = (unsigned long) 1 << (drawable->depth - 1); i; i >>= 1) {
190			if (i & gc->planemask) {
191				fbPutXYImage(drawable, gc,
192					     FB_ALLONES,
193					     0,
194					     fbReplicatePixel(i, drawable->bitsPerPixel),
195					     gc->alu,
196					     TRUE, x, y, w, h, src, srcStride, leftPad);
197				src += srcStride * h;
198			}
199		}
200		break;
201	case ZPixmap:
202		srcStride = PixmapBytePad(w, drawable->depth) / sizeof(FbStip);
203		fbPutZImage(drawable, gc,
204			    x, y, w, h, src, srcStride);
205	}
206}
207
208void
209fbGetImage(DrawablePtr drawable,
210           int x, int y, int w, int h,
211	   unsigned int format, unsigned long planeMask, char *d)
212{
213	FbBits *src;
214	FbStride srcStride;
215	int srcBpp;
216	int srcXoff, srcYoff;
217	FbStip *dst;
218	FbStride dstStride;
219
220	DBG(("%s (%d, %d)x(%d, %d)\n", __FUNCTION__, x, y, w, h));
221
222	fbGetDrawable(drawable, src, srcStride, srcBpp, srcXoff, srcYoff);
223
224	x += drawable->x;
225	y += drawable->y;
226
227	dst = (FbStip *) d;
228	if (format == ZPixmap || srcBpp == 1) {
229		FbBits pm;
230
231		pm = fbReplicatePixel(planeMask, srcBpp);
232
233		dstStride = PixmapBytePad(w, drawable->depth);
234		dstStride /= sizeof(FbStip);
235
236		fbBltStip((FbStip *)(src + (y + srcYoff) * srcStride), srcStride,
237			  (x + srcXoff) * srcBpp,
238			  dst, dstStride, 0, w * srcBpp, h, GXcopy, FB_ALLONES, srcBpp);
239
240		if (pm != FB_ALLONES) {
241			int i = dstStride * h;
242			while (i--)
243				*dst++ &= pm;
244		}
245	} else {
246		dstStride = BitmapBytePad(w) / sizeof(FbStip);
247		fbBltPlane(src + (y + srcYoff) * srcStride,
248			   srcStride,
249			   (x + srcXoff) * srcBpp,
250			   srcBpp,
251			   dst,
252			   dstStride,
253			   0,
254			   w * srcBpp, h,
255			   fbAndStip(GXcopy, FB_STIP_ALLONES, FB_STIP_ALLONES),
256			   fbXorStip(GXcopy, FB_STIP_ALLONES, FB_STIP_ALLONES),
257			   fbAndStip(GXcopy, 0, FB_STIP_ALLONES),
258			   fbXorStip(GXcopy, 0, FB_STIP_ALLONES), planeMask);
259	}
260}
261