Commit | Line | Data |
---|---|---|
a09e091a JB |
1 | /* |
2 | * | |
3 | * Copyright © 1998 Keith Packard | |
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 | #ifdef HAVE_DIX_CONFIG_H | |
25 | #include <dix-config.h> | |
26 | #endif | |
27 | ||
28 | #include "fb.h" | |
29 | #include <X11/fonts/fontstruct.h> | |
30 | #include "dixfontstr.h" | |
31 | ||
32 | Bool | |
33 | fbGlyphIn(RegionPtr pRegion, int x, int y, int width, int height) | |
34 | { | |
35 | BoxRec box; | |
36 | BoxPtr pExtents = RegionExtents(pRegion); | |
37 | ||
38 | /* | |
39 | * Check extents by hand to avoid 16 bit overflows | |
40 | */ | |
41 | if (x < (int) pExtents->x1) | |
42 | return FALSE; | |
43 | if ((int) pExtents->x2 < x + width) | |
44 | return FALSE; | |
45 | if (y < (int) pExtents->y1) | |
46 | return FALSE; | |
47 | if ((int) pExtents->y2 < y + height) | |
48 | return FALSE; | |
49 | box.x1 = x; | |
50 | box.x2 = x + width; | |
51 | box.y1 = y; | |
52 | box.y2 = y + height; | |
53 | return RegionContainsRect(pRegion, &box) == rgnIN; | |
54 | } | |
55 | ||
56 | #define WRITE1(d,n,fg) WRITE((d) + (n), (CARD8) fg) | |
57 | #define WRITE2(d,n,fg) WRITE((CARD16 *) &(d[n]), (CARD16) fg) | |
58 | #define WRITE4(d,n,fg) WRITE((CARD32 *) &(d[n]), (CARD32) fg) | |
59 | #if FB_UNIT == 6 && IMAGE_BYTE_ORDER == LSBFirst | |
60 | #define WRITE8(d) WRITE((FbBits *) &(d[0]), fg) | |
61 | #else | |
62 | #define WRITE8(d) WRITE4(d,0,_ABCA), WRITE4(d,4,_BCAB) | |
63 | #endif | |
64 | ||
65 | /* | |
66 | * This is a bit tricky, but it's brief. Write 12 bytes worth | |
67 | * of dest, which is four pixels, at a time. This gives constant | |
68 | * code for each pattern as they're always aligned the same | |
69 | * | |
70 | * a b c d a b c d a b c d bytes | |
71 | * A B C A B C A B C A B C pixels | |
72 | * | |
73 | * f0 f1 f2 | |
74 | * A B C A B C A B C A B C pixels LSB | |
75 | * C A B C A B C A B C A B pixels MSB | |
76 | * | |
77 | * LSB MSB | |
78 | * A f0 f1 | |
79 | * B f1 f2 | |
80 | * C f2 f0 | |
81 | * A B f0 f2 | |
82 | * B C f1 f0 | |
83 | * C A f2 f1 | |
84 | * A B C A f0 f1 | |
85 | * B C A B f1 f2 | |
86 | * C A B C f2 f0 | |
87 | */ | |
88 | ||
89 | #undef _A | |
90 | #undef _B | |
91 | #undef _C | |
92 | #undef _AB | |
93 | #undef _BC | |
94 | #undef _CA | |
95 | #undef _ABCA | |
96 | #undef _BCAB | |
97 | #undef _CABC | |
98 | ||
99 | #if IMAGE_BYTE_ORDER == MSBFirst | |
100 | #define _A f1 | |
101 | #define _B f2 | |
102 | #define _C f0 | |
103 | #define _AB f2 | |
104 | #define _BC f0 | |
105 | #define _CA f1 | |
106 | #define _ABCA f1 | |
107 | #define _BCAB f2 | |
108 | #define _CABC f0 | |
109 | #define CASE(a,b,c,d) ((a << 3) | (b << 2) | (c << 1) | d) | |
110 | #else | |
111 | #define _A f0 | |
112 | #define _B f1 | |
113 | #define _C f2 | |
114 | #define _AB f0 | |
115 | #define _BC f1 | |
116 | #define _CA f2 | |
117 | #define _ABCA f0 | |
118 | #define _BCAB f1 | |
119 | #define _CABC f2 | |
120 | #define CASE(a,b,c,d) (a | (b << 1) | (c << 2) | (d << 3)) | |
121 | #endif | |
122 | ||
123 | void | |
124 | fbGlyph24(FbBits * dstBits, | |
125 | FbStride dstStride, | |
126 | int dstBpp, FbStip * stipple, FbBits fg, int x, int height) | |
127 | { | |
128 | int lshift; | |
129 | FbStip bits; | |
130 | CARD8 *dstLine; | |
131 | CARD8 *dst; | |
132 | FbStip f0, f1, f2; | |
133 | int n; | |
134 | int shift; | |
135 | ||
136 | f0 = fg; | |
137 | f1 = FbRot24(f0, 16); | |
138 | f2 = FbRot24(f0, 8); | |
139 | ||
140 | dstLine = (CARD8 *) dstBits; | |
141 | dstLine += (x & ~3) * 3; | |
142 | dstStride *= (sizeof(FbBits) / sizeof(CARD8)); | |
143 | shift = x & 3; | |
144 | lshift = 4 - shift; | |
145 | while (height--) { | |
146 | bits = READ(stipple++); | |
147 | n = lshift; | |
148 | dst = dstLine; | |
149 | while (bits) { | |
150 | switch (FbStipMoveLsb(FbLeftStipBits(bits, n), 4, n)) { | |
151 | case CASE(0, 0, 0, 0): | |
152 | break; | |
153 | case CASE(1, 0, 0, 0): | |
154 | WRITE2(dst, 0, _AB); | |
155 | WRITE1(dst, 2, _C); | |
156 | break; | |
157 | case CASE(0, 1, 0, 0): | |
158 | WRITE1(dst, 3, _A); | |
159 | WRITE2(dst, 4, _BC); | |
160 | break; | |
161 | case CASE(1, 1, 0, 0): | |
162 | WRITE4(dst, 0, _ABCA); | |
163 | WRITE2(dst, 4, _BC); | |
164 | break; | |
165 | case CASE(0, 0, 1, 0): | |
166 | WRITE2(dst, 6, _AB); | |
167 | WRITE1(dst, 8, _C); | |
168 | break; | |
169 | case CASE(1, 0, 1, 0): | |
170 | WRITE2(dst, 0, _AB); | |
171 | WRITE1(dst, 2, _C); | |
172 | ||
173 | WRITE2(dst, 6, _AB); | |
174 | WRITE1(dst, 8, _C); | |
175 | break; | |
176 | case CASE(0, 1, 1, 0): | |
177 | WRITE1(dst, 3, _A); | |
178 | WRITE4(dst, 4, _BCAB); | |
179 | WRITE1(dst, 8, _C); | |
180 | break; | |
181 | case CASE(1, 1, 1, 0): | |
182 | WRITE8(dst); | |
183 | WRITE1(dst, 8, _C); | |
184 | break; | |
185 | case CASE(0, 0, 0, 1): | |
186 | WRITE1(dst, 9, _A); | |
187 | WRITE2(dst, 10, _BC); | |
188 | break; | |
189 | case CASE(1, 0, 0, 1): | |
190 | WRITE2(dst, 0, _AB); | |
191 | WRITE1(dst, 2, _C); | |
192 | ||
193 | WRITE1(dst, 9, _A); | |
194 | WRITE2(dst, 10, _BC); | |
195 | break; | |
196 | case CASE(0, 1, 0, 1): | |
197 | WRITE1(dst, 3, _A); | |
198 | WRITE2(dst, 4, _BC); | |
199 | ||
200 | WRITE1(dst, 9, _A); | |
201 | WRITE2(dst, 10, _BC); | |
202 | break; | |
203 | case CASE(1, 1, 0, 1): | |
204 | WRITE4(dst, 0, _ABCA); | |
205 | WRITE2(dst, 4, _BC); | |
206 | ||
207 | WRITE1(dst, 9, _A); | |
208 | WRITE2(dst, 10, _BC); | |
209 | break; | |
210 | case CASE(0, 0, 1, 1): | |
211 | WRITE2(dst, 6, _AB); | |
212 | WRITE4(dst, 8, _CABC); | |
213 | break; | |
214 | case CASE(1, 0, 1, 1): | |
215 | WRITE2(dst, 0, _AB); | |
216 | WRITE1(dst, 2, _C); | |
217 | ||
218 | WRITE2(dst, 6, _AB); | |
219 | WRITE4(dst, 8, _CABC); | |
220 | break; | |
221 | case CASE(0, 1, 1, 1): | |
222 | WRITE1(dst, 3, _A); | |
223 | WRITE4(dst, 4, _BCAB); | |
224 | WRITE4(dst, 8, _CABC); | |
225 | break; | |
226 | case CASE(1, 1, 1, 1): | |
227 | WRITE8(dst); | |
228 | WRITE4(dst, 8, _CABC); | |
229 | break; | |
230 | } | |
231 | bits = FbStipLeft(bits, n); | |
232 | n = 4; | |
233 | dst += 12; | |
234 | } | |
235 | dstLine += dstStride; | |
236 | } | |
237 | } | |
238 | ||
239 | void | |
240 | fbPolyGlyphBlt(DrawablePtr pDrawable, | |
241 | GCPtr pGC, | |
242 | int x, | |
243 | int y, | |
244 | unsigned int nglyph, CharInfoPtr * ppci, pointer pglyphBase) | |
245 | { | |
246 | FbGCPrivPtr pPriv = fbGetGCPrivate(pGC); | |
247 | CharInfoPtr pci; | |
248 | unsigned char *pglyph; /* pointer bits in glyph */ | |
249 | int gx, gy; | |
250 | int gWidth, gHeight; /* width and height of glyph */ | |
251 | FbStride gStride; /* stride of glyph */ | |
252 | void (*glyph) (FbBits *, FbStride, int, FbStip *, FbBits, int, int); | |
253 | FbBits *dst = 0; | |
254 | FbStride dstStride = 0; | |
255 | int dstBpp = 0; | |
256 | int dstXoff = 0, dstYoff = 0; | |
257 | ||
258 | glyph = 0; | |
259 | if (pGC->fillStyle == FillSolid && pPriv->and == 0) { | |
260 | dstBpp = pDrawable->bitsPerPixel; | |
261 | switch (dstBpp) { | |
262 | case 8: | |
263 | glyph = fbGlyph8; | |
264 | break; | |
265 | case 16: | |
266 | glyph = fbGlyph16; | |
267 | break; | |
268 | case 24: | |
269 | glyph = fbGlyph24; | |
270 | break; | |
271 | case 32: | |
272 | glyph = fbGlyph32; | |
273 | break; | |
274 | } | |
275 | } | |
276 | x += pDrawable->x; | |
277 | y += pDrawable->y; | |
278 | ||
279 | while (nglyph--) { | |
280 | pci = *ppci++; | |
281 | pglyph = FONTGLYPHBITS(pglyphBase, pci); | |
282 | gWidth = GLYPHWIDTHPIXELS(pci); | |
283 | gHeight = GLYPHHEIGHTPIXELS(pci); | |
284 | if (gWidth && gHeight) { | |
285 | gx = x + pci->metrics.leftSideBearing; | |
286 | gy = y - pci->metrics.ascent; | |
287 | if (glyph && gWidth <= sizeof(FbStip) * 8 && | |
288 | fbGlyphIn(fbGetCompositeClip(pGC), gx, gy, gWidth, gHeight)) { | |
289 | fbGetDrawable(pDrawable, dst, dstStride, dstBpp, dstXoff, | |
290 | dstYoff); | |
291 | (*glyph) (dst + (gy + dstYoff) * dstStride, dstStride, dstBpp, | |
292 | (FbStip *) pglyph, pPriv->xor, gx + dstXoff, gHeight); | |
293 | fbFinishAccess(pDrawable); | |
294 | } | |
295 | else { | |
296 | gStride = GLYPHWIDTHBYTESPADDED(pci) / sizeof(FbStip); | |
297 | fbPushImage(pDrawable, | |
298 | pGC, | |
299 | (FbStip *) pglyph, | |
300 | gStride, 0, gx, gy, gWidth, gHeight); | |
301 | } | |
302 | } | |
303 | x += pci->metrics.characterWidth; | |
304 | } | |
305 | } | |
306 | ||
307 | void | |
308 | fbImageGlyphBlt(DrawablePtr pDrawable, | |
309 | GCPtr pGC, | |
310 | int x, | |
311 | int y, | |
312 | unsigned int nglyph, CharInfoPtr * ppciInit, pointer pglyphBase) | |
313 | { | |
314 | FbGCPrivPtr pPriv = fbGetGCPrivate(pGC); | |
315 | CharInfoPtr *ppci; | |
316 | CharInfoPtr pci; | |
317 | unsigned char *pglyph; /* pointer bits in glyph */ | |
318 | int gWidth, gHeight; /* width and height of glyph */ | |
319 | FbStride gStride; /* stride of glyph */ | |
320 | Bool opaque; | |
321 | int n; | |
322 | int gx, gy; | |
323 | void (*glyph) (FbBits *, FbStride, int, FbStip *, FbBits, int, int); | |
324 | FbBits *dst = 0; | |
325 | FbStride dstStride = 0; | |
326 | int dstBpp = 0; | |
327 | int dstXoff = 0, dstYoff = 0; | |
328 | ||
329 | glyph = 0; | |
330 | if (pPriv->and == 0) { | |
331 | dstBpp = pDrawable->bitsPerPixel; | |
332 | switch (dstBpp) { | |
333 | case 8: | |
334 | glyph = fbGlyph8; | |
335 | break; | |
336 | case 16: | |
337 | glyph = fbGlyph16; | |
338 | break; | |
339 | case 24: | |
340 | glyph = fbGlyph24; | |
341 | break; | |
342 | case 32: | |
343 | glyph = fbGlyph32; | |
344 | break; | |
345 | } | |
346 | } | |
347 | ||
348 | x += pDrawable->x; | |
349 | y += pDrawable->y; | |
350 | ||
351 | if (TERMINALFONT(pGC->font) | |
352 | && !glyph) { | |
353 | opaque = TRUE; | |
354 | } | |
355 | else { | |
356 | int xBack, widthBack; | |
357 | int yBack, heightBack; | |
358 | ||
359 | ppci = ppciInit; | |
360 | n = nglyph; | |
361 | widthBack = 0; | |
362 | while (n--) | |
363 | widthBack += (*ppci++)->metrics.characterWidth; | |
364 | ||
365 | xBack = x; | |
366 | if (widthBack < 0) { | |
367 | xBack += widthBack; | |
368 | widthBack = -widthBack; | |
369 | } | |
370 | yBack = y - FONTASCENT(pGC->font); | |
371 | heightBack = FONTASCENT(pGC->font) + FONTDESCENT(pGC->font); | |
372 | fbSolidBoxClipped(pDrawable, | |
373 | fbGetCompositeClip(pGC), | |
374 | xBack, | |
375 | yBack, | |
376 | xBack + widthBack, | |
377 | yBack + heightBack, | |
378 | fbAnd(GXcopy, pPriv->bg, pPriv->pm), | |
379 | fbXor(GXcopy, pPriv->bg, pPriv->pm)); | |
380 | opaque = FALSE; | |
381 | } | |
382 | ||
383 | ppci = ppciInit; | |
384 | while (nglyph--) { | |
385 | pci = *ppci++; | |
386 | pglyph = FONTGLYPHBITS(pglyphBase, pci); | |
387 | gWidth = GLYPHWIDTHPIXELS(pci); | |
388 | gHeight = GLYPHHEIGHTPIXELS(pci); | |
389 | if (gWidth && gHeight) { | |
390 | gx = x + pci->metrics.leftSideBearing; | |
391 | gy = y - pci->metrics.ascent; | |
392 | if (glyph && gWidth <= sizeof(FbStip) * 8 && | |
393 | fbGlyphIn(fbGetCompositeClip(pGC), gx, gy, gWidth, gHeight)) { | |
394 | fbGetDrawable(pDrawable, dst, dstStride, dstBpp, dstXoff, | |
395 | dstYoff); | |
396 | (*glyph) (dst + (gy + dstYoff) * dstStride, dstStride, dstBpp, | |
397 | (FbStip *) pglyph, pPriv->fg, gx + dstXoff, gHeight); | |
398 | fbFinishAccess(pDrawable); | |
399 | } | |
400 | else { | |
401 | gStride = GLYPHWIDTHBYTESPADDED(pci) / sizeof(FbStip); | |
402 | fbPutXYImage(pDrawable, | |
403 | fbGetCompositeClip(pGC), | |
404 | pPriv->fg, | |
405 | pPriv->bg, | |
406 | pPriv->pm, | |
407 | GXcopy, | |
408 | opaque, | |
409 | gx, | |
410 | gy, | |
411 | gWidth, gHeight, (FbStip *) pglyph, gStride, 0); | |
412 | } | |
413 | } | |
414 | x += pci->metrics.characterWidth; | |
415 | } | |
416 | } |