fbglyph.c revision 35c4bbdf
17ec681f3Smrg/* 27ec681f3Smrg * 37ec681f3Smrg * Copyright © 1998 Keith Packard 47ec681f3Smrg * 57ec681f3Smrg * Permission to use, copy, modify, distribute, and sell this software and its 67ec681f3Smrg * documentation for any purpose is hereby granted without fee, provided that 77ec681f3Smrg * the above copyright notice appear in all copies and that both that 87ec681f3Smrg * copyright notice and this permission notice appear in supporting 97ec681f3Smrg * documentation, and that the name of Keith Packard not be used in 107ec681f3Smrg * advertising or publicity pertaining to distribution of the software without 117ec681f3Smrg * specific, written prior permission. Keith Packard makes no 127ec681f3Smrg * representations about the suitability of this software for any purpose. It 137ec681f3Smrg * is provided "as is" without express or implied warranty. 147ec681f3Smrg * 157ec681f3Smrg * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 167ec681f3Smrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 177ec681f3Smrg * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR 187ec681f3Smrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 197ec681f3Smrg * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 207ec681f3Smrg * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 217ec681f3Smrg * PERFORMANCE OF THIS SOFTWARE. 227ec681f3Smrg */ 237ec681f3Smrg 247ec681f3Smrg#ifdef HAVE_DIX_CONFIG_H 257ec681f3Smrg#include <dix-config.h> 267ec681f3Smrg#endif 277ec681f3Smrg 287ec681f3Smrg#include "fb.h" 297ec681f3Smrg#include <X11/fonts/fontstruct.h> 307ec681f3Smrg#include "dixfontstr.h" 317ec681f3Smrg 327ec681f3Smrgstatic Bool 337ec681f3SmrgfbGlyphIn(RegionPtr pRegion, int x, int y, int width, int height) 347ec681f3Smrg{ 357ec681f3Smrg BoxRec box; 367ec681f3Smrg BoxPtr pExtents = RegionExtents(pRegion); 377ec681f3Smrg 387ec681f3Smrg /* 397ec681f3Smrg * Check extents by hand to avoid 16 bit overflows 407ec681f3Smrg */ 417ec681f3Smrg if (x < (int) pExtents->x1) 427ec681f3Smrg return FALSE; 437ec681f3Smrg if ((int) pExtents->x2 < x + width) 447ec681f3Smrg return FALSE; 457ec681f3Smrg if (y < (int) pExtents->y1) 467ec681f3Smrg return FALSE; 477ec681f3Smrg if ((int) pExtents->y2 < y + height) 487ec681f3Smrg return FALSE; 497ec681f3Smrg box.x1 = x; 507ec681f3Smrg box.x2 = x + width; 517ec681f3Smrg box.y1 = y; 527ec681f3Smrg box.y2 = y + height; 537ec681f3Smrg return RegionContainsRect(pRegion, &box) == rgnIN; 547ec681f3Smrg} 557ec681f3Smrg 567ec681f3Smrg#define WRITE1(d,n,fg) WRITE((d) + (n), (CARD8) fg) 577ec681f3Smrg#define WRITE2(d,n,fg) WRITE((CARD16 *) &(d[n]), (CARD16) fg) 587ec681f3Smrg#define WRITE4(d,n,fg) WRITE((CARD32 *) &(d[n]), (CARD32) fg) 597ec681f3Smrg#define WRITE8(d) WRITE4(d,0,_ABCA), WRITE4(d,4,_BCAB) 607ec681f3Smrg 617ec681f3Smrg/* 627ec681f3Smrg * This is a bit tricky, but it's brief. Write 12 bytes worth 637ec681f3Smrg * of dest, which is four pixels, at a time. This gives constant 647ec681f3Smrg * code for each pattern as they're always aligned the same 657ec681f3Smrg * 667ec681f3Smrg * a b c d a b c d a b c d bytes 677ec681f3Smrg * A B C A B C A B C A B C pixels 687ec681f3Smrg * 697ec681f3Smrg * f0 f1 f2 707ec681f3Smrg * A B C A B C A B C A B C pixels LSB 717ec681f3Smrg * C A B C A B C A B C A B pixels MSB 727ec681f3Smrg * 737ec681f3Smrg * LSB MSB 747ec681f3Smrg * A f0 f1 757ec681f3Smrg * B f1 f2 767ec681f3Smrg * C f2 f0 777ec681f3Smrg * A B f0 f2 787ec681f3Smrg * B C f1 f0 797ec681f3Smrg * C A f2 f1 807ec681f3Smrg * A B C A f0 f1 817ec681f3Smrg * B C A B f1 f2 827ec681f3Smrg * C A B C f2 f0 837ec681f3Smrg */ 847ec681f3Smrg 857ec681f3Smrg#undef _A 867ec681f3Smrg#undef _B 877ec681f3Smrg#undef _C 887ec681f3Smrg#undef _AB 897ec681f3Smrg#undef _BC 907ec681f3Smrg#undef _CA 917ec681f3Smrg#undef _ABCA 927ec681f3Smrg#undef _BCAB 937ec681f3Smrg#undef _CABC 947ec681f3Smrg 957ec681f3Smrg#if IMAGE_BYTE_ORDER == MSBFirst 967ec681f3Smrg#define _A f1 977ec681f3Smrg#define _B f2 987ec681f3Smrg#define _C f0 997ec681f3Smrg#define _AB f2 1007ec681f3Smrg#define _BC f0 1017ec681f3Smrg#define _CA f1 1027ec681f3Smrg#define _ABCA f1 1037ec681f3Smrg#define _BCAB f2 1047ec681f3Smrg#define _CABC f0 1057ec681f3Smrg#define CASE(a,b,c,d) ((a << 3) | (b << 2) | (c << 1) | d) 1067ec681f3Smrg#else 1077ec681f3Smrg#define _A f0 1087ec681f3Smrg#define _B f1 1097ec681f3Smrg#define _C f2 1107ec681f3Smrg#define _AB f0 1117ec681f3Smrg#define _BC f1 1127ec681f3Smrg#define _CA f2 1137ec681f3Smrg#define _ABCA f0 1147ec681f3Smrg#define _BCAB f1 1157ec681f3Smrg#define _CABC f2 1167ec681f3Smrg#define CASE(a,b,c,d) (a | (b << 1) | (c << 2) | (d << 3)) 1177ec681f3Smrg#endif 1187ec681f3Smrg 1197ec681f3Smrgstatic void 1207ec681f3SmrgfbGlyph24(FbBits * dstBits, 1217ec681f3Smrg FbStride dstStride, 1227ec681f3Smrg int dstBpp, FbStip * stipple, FbBits fg, int x, int height) 1237ec681f3Smrg{ 1247ec681f3Smrg int lshift; 1257ec681f3Smrg FbStip bits; 1267ec681f3Smrg CARD8 *dstLine; 1277ec681f3Smrg CARD8 *dst; 1287ec681f3Smrg FbStip f0, f1, f2; 1297ec681f3Smrg int n; 1307ec681f3Smrg int shift; 1317ec681f3Smrg 1327ec681f3Smrg f0 = fg; 1337ec681f3Smrg f1 = FbRot24(f0, 16); 1347ec681f3Smrg f2 = FbRot24(f0, 8); 1357ec681f3Smrg 1367ec681f3Smrg dstLine = (CARD8 *) dstBits; 1377ec681f3Smrg dstLine += (x & ~3) * 3; 1387ec681f3Smrg dstStride *= (sizeof(FbBits) / sizeof(CARD8)); 1397ec681f3Smrg shift = x & 3; 1407ec681f3Smrg lshift = 4 - shift; 1417ec681f3Smrg while (height--) { 1427ec681f3Smrg bits = READ(stipple++); 1437ec681f3Smrg n = lshift; 1447ec681f3Smrg dst = dstLine; 1457ec681f3Smrg while (bits) { 1467ec681f3Smrg switch (FbStipMoveLsb(FbLeftStipBits(bits, n), 4, n)) { 1477ec681f3Smrg case CASE(0, 0, 0, 0): 1487ec681f3Smrg break; 1497ec681f3Smrg case CASE(1, 0, 0, 0): 1507ec681f3Smrg WRITE2(dst, 0, _AB); 1517ec681f3Smrg WRITE1(dst, 2, _C); 1527ec681f3Smrg break; 1537ec681f3Smrg case CASE(0, 1, 0, 0): 1547ec681f3Smrg WRITE1(dst, 3, _A); 1557ec681f3Smrg WRITE2(dst, 4, _BC); 1567ec681f3Smrg break; 1577ec681f3Smrg case CASE(1, 1, 0, 0): 1587ec681f3Smrg WRITE4(dst, 0, _ABCA); 1597ec681f3Smrg WRITE2(dst, 4, _BC); 1607ec681f3Smrg break; 1617ec681f3Smrg case CASE(0, 0, 1, 0): 1627ec681f3Smrg WRITE2(dst, 6, _AB); 1637ec681f3Smrg WRITE1(dst, 8, _C); 1647ec681f3Smrg break; 1657ec681f3Smrg case CASE(1, 0, 1, 0): 1667ec681f3Smrg WRITE2(dst, 0, _AB); 1677ec681f3Smrg WRITE1(dst, 2, _C); 1687ec681f3Smrg 1697ec681f3Smrg WRITE2(dst, 6, _AB); 1707ec681f3Smrg WRITE1(dst, 8, _C); 1717ec681f3Smrg break; 1727ec681f3Smrg case CASE(0, 1, 1, 0): 1737ec681f3Smrg WRITE1(dst, 3, _A); 1747ec681f3Smrg WRITE4(dst, 4, _BCAB); 1757ec681f3Smrg WRITE1(dst, 8, _C); 1767ec681f3Smrg break; 1777ec681f3Smrg case CASE(1, 1, 1, 0): 1787ec681f3Smrg WRITE8(dst); 1797ec681f3Smrg WRITE1(dst, 8, _C); 1807ec681f3Smrg break; 1817ec681f3Smrg case CASE(0, 0, 0, 1): 1827ec681f3Smrg WRITE1(dst, 9, _A); 1837ec681f3Smrg WRITE2(dst, 10, _BC); 1847ec681f3Smrg break; 1857ec681f3Smrg case CASE(1, 0, 0, 1): 1867ec681f3Smrg WRITE2(dst, 0, _AB); 1877ec681f3Smrg WRITE1(dst, 2, _C); 1887ec681f3Smrg 1897ec681f3Smrg WRITE1(dst, 9, _A); 1907ec681f3Smrg WRITE2(dst, 10, _BC); 1917ec681f3Smrg break; 1927ec681f3Smrg case CASE(0, 1, 0, 1): 1937ec681f3Smrg WRITE1(dst, 3, _A); 1947ec681f3Smrg WRITE2(dst, 4, _BC); 1957ec681f3Smrg 1967ec681f3Smrg WRITE1(dst, 9, _A); 1977ec681f3Smrg WRITE2(dst, 10, _BC); 1987ec681f3Smrg break; 1997ec681f3Smrg case CASE(1, 1, 0, 1): 2007ec681f3Smrg WRITE4(dst, 0, _ABCA); 2017ec681f3Smrg WRITE2(dst, 4, _BC); 2027ec681f3Smrg 2037ec681f3Smrg WRITE1(dst, 9, _A); 2047ec681f3Smrg WRITE2(dst, 10, _BC); 2057ec681f3Smrg break; 2067ec681f3Smrg case CASE(0, 0, 1, 1): 2077ec681f3Smrg WRITE2(dst, 6, _AB); 2087ec681f3Smrg WRITE4(dst, 8, _CABC); 2097ec681f3Smrg break; 2107ec681f3Smrg case CASE(1, 0, 1, 1): 2117ec681f3Smrg WRITE2(dst, 0, _AB); 2127ec681f3Smrg WRITE1(dst, 2, _C); 2137ec681f3Smrg 2147ec681f3Smrg WRITE2(dst, 6, _AB); 215 WRITE4(dst, 8, _CABC); 216 break; 217 case CASE(0, 1, 1, 1): 218 WRITE1(dst, 3, _A); 219 WRITE4(dst, 4, _BCAB); 220 WRITE4(dst, 8, _CABC); 221 break; 222 case CASE(1, 1, 1, 1): 223 WRITE8(dst); 224 WRITE4(dst, 8, _CABC); 225 break; 226 } 227 bits = FbStipLeft(bits, n); 228 n = 4; 229 dst += 12; 230 } 231 dstLine += dstStride; 232 } 233} 234 235void 236fbPolyGlyphBlt(DrawablePtr pDrawable, 237 GCPtr pGC, 238 int x, 239 int y, 240 unsigned int nglyph, CharInfoPtr * ppci, void *pglyphBase) 241{ 242 FbGCPrivPtr pPriv = fbGetGCPrivate(pGC); 243 CharInfoPtr pci; 244 unsigned char *pglyph; /* pointer bits in glyph */ 245 int gx, gy; 246 int gWidth, gHeight; /* width and height of glyph */ 247 FbStride gStride; /* stride of glyph */ 248 void (*glyph) (FbBits *, FbStride, int, FbStip *, FbBits, int, int); 249 FbBits *dst = 0; 250 FbStride dstStride = 0; 251 int dstBpp = 0; 252 int dstXoff = 0, dstYoff = 0; 253 254 glyph = 0; 255 if (pGC->fillStyle == FillSolid && pPriv->and == 0) { 256 dstBpp = pDrawable->bitsPerPixel; 257 switch (dstBpp) { 258 case 8: 259 glyph = fbGlyph8; 260 break; 261 case 16: 262 glyph = fbGlyph16; 263 break; 264 case 24: 265 glyph = fbGlyph24; 266 break; 267 case 32: 268 glyph = fbGlyph32; 269 break; 270 } 271 } 272 x += pDrawable->x; 273 y += pDrawable->y; 274 275 while (nglyph--) { 276 pci = *ppci++; 277 pglyph = FONTGLYPHBITS(pglyphBase, pci); 278 gWidth = GLYPHWIDTHPIXELS(pci); 279 gHeight = GLYPHHEIGHTPIXELS(pci); 280 if (gWidth && gHeight) { 281 gx = x + pci->metrics.leftSideBearing; 282 gy = y - pci->metrics.ascent; 283 if (glyph && gWidth <= sizeof(FbStip) * 8 && 284 fbGlyphIn(fbGetCompositeClip(pGC), gx, gy, gWidth, gHeight)) { 285 fbGetDrawable(pDrawable, dst, dstStride, dstBpp, dstXoff, 286 dstYoff); 287 (*glyph) (dst + (gy + dstYoff) * dstStride, dstStride, dstBpp, 288 (FbStip *) pglyph, pPriv->xor, gx + dstXoff, gHeight); 289 fbFinishAccess(pDrawable); 290 } 291 else { 292 gStride = GLYPHWIDTHBYTESPADDED(pci) / sizeof(FbStip); 293 fbPushImage(pDrawable, 294 pGC, 295 (FbStip *) pglyph, 296 gStride, 0, gx, gy, gWidth, gHeight); 297 } 298 } 299 x += pci->metrics.characterWidth; 300 } 301} 302 303void 304fbImageGlyphBlt(DrawablePtr pDrawable, 305 GCPtr pGC, 306 int x, 307 int y, 308 unsigned int nglyph, CharInfoPtr * ppciInit, void *pglyphBase) 309{ 310 FbGCPrivPtr pPriv = fbGetGCPrivate(pGC); 311 CharInfoPtr *ppci; 312 CharInfoPtr pci; 313 unsigned char *pglyph; /* pointer bits in glyph */ 314 int gWidth, gHeight; /* width and height of glyph */ 315 FbStride gStride; /* stride of glyph */ 316 Bool opaque; 317 int n; 318 int gx, gy; 319 void (*glyph) (FbBits *, FbStride, int, FbStip *, FbBits, int, int); 320 FbBits *dst = 0; 321 FbStride dstStride = 0; 322 int dstBpp = 0; 323 int dstXoff = 0, dstYoff = 0; 324 325 glyph = 0; 326 if (pPriv->and == 0) { 327 dstBpp = pDrawable->bitsPerPixel; 328 switch (dstBpp) { 329 case 8: 330 glyph = fbGlyph8; 331 break; 332 case 16: 333 glyph = fbGlyph16; 334 break; 335 case 24: 336 glyph = fbGlyph24; 337 break; 338 case 32: 339 glyph = fbGlyph32; 340 break; 341 } 342 } 343 344 x += pDrawable->x; 345 y += pDrawable->y; 346 347 if (TERMINALFONT(pGC->font) 348 && !glyph) { 349 opaque = TRUE; 350 } 351 else { 352 int xBack, widthBack; 353 int yBack, heightBack; 354 355 ppci = ppciInit; 356 n = nglyph; 357 widthBack = 0; 358 while (n--) 359 widthBack += (*ppci++)->metrics.characterWidth; 360 361 xBack = x; 362 if (widthBack < 0) { 363 xBack += widthBack; 364 widthBack = -widthBack; 365 } 366 yBack = y - FONTASCENT(pGC->font); 367 heightBack = FONTASCENT(pGC->font) + FONTDESCENT(pGC->font); 368 fbSolidBoxClipped(pDrawable, 369 fbGetCompositeClip(pGC), 370 xBack, 371 yBack, 372 xBack + widthBack, 373 yBack + heightBack, 374 fbAnd(GXcopy, pPriv->bg, pPriv->pm), 375 fbXor(GXcopy, pPriv->bg, pPriv->pm)); 376 opaque = FALSE; 377 } 378 379 ppci = ppciInit; 380 while (nglyph--) { 381 pci = *ppci++; 382 pglyph = FONTGLYPHBITS(pglyphBase, pci); 383 gWidth = GLYPHWIDTHPIXELS(pci); 384 gHeight = GLYPHHEIGHTPIXELS(pci); 385 if (gWidth && gHeight) { 386 gx = x + pci->metrics.leftSideBearing; 387 gy = y - pci->metrics.ascent; 388 if (glyph && gWidth <= sizeof(FbStip) * 8 && 389 fbGlyphIn(fbGetCompositeClip(pGC), gx, gy, gWidth, gHeight)) { 390 fbGetDrawable(pDrawable, dst, dstStride, dstBpp, dstXoff, 391 dstYoff); 392 (*glyph) (dst + (gy + dstYoff) * dstStride, dstStride, dstBpp, 393 (FbStip *) pglyph, pPriv->fg, gx + dstXoff, gHeight); 394 fbFinishAccess(pDrawable); 395 } 396 else { 397 gStride = GLYPHWIDTHBYTESPADDED(pci) / sizeof(FbStip); 398 fbPutXYImage(pDrawable, 399 fbGetCompositeClip(pGC), 400 pPriv->fg, 401 pPriv->bg, 402 pPriv->pm, 403 GXcopy, 404 opaque, 405 gx, 406 gy, 407 gWidth, gHeight, (FbStip *) pglyph, gStride, 0); 408 } 409 } 410 x += pci->metrics.characterWidth; 411 } 412} 413