exa_glyphs.c revision 4642e01f
1/* 2 * Copyright © 2008 Red Hat, Inc. 3 * Partly based on code Copyright © 2000 SuSE, Inc. 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 Red Hat not be used in advertising or 10 * publicity pertaining to distribution of the software without specific, 11 * written prior permission. Red Hat makes no representations about the 12 * suitability of this software for any purpose. It is provided "as is" 13 * without express or implied warranty. 14 * 15 * Red Hat DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL Red Hat 17 * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 18 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 19 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 20 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 21 * 22 * Permission to use, copy, modify, distribute, and sell this software and its 23 * documentation for any purpose is hereby granted without fee, provided that 24 * the above copyright notice appear in all copies and that both that 25 * copyright notice and this permission notice appear in supporting 26 * documentation, and that the name of SuSE not be used in advertising or 27 * publicity pertaining to distribution of the software without specific, 28 * written prior permission. SuSE makes no representations about the 29 * suitability of this software for any purpose. It is provided "as is" 30 * without express or implied warranty. 31 * 32 * SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL 33 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE 34 * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 35 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 36 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 37 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 38 * 39 * Author: Owen Taylor <otaylor@fishsoup.net> 40 * Based on code by: Keith Packard 41 */ 42 43#ifdef HAVE_DIX_CONFIG_H 44#include <dix-config.h> 45#endif 46 47#include <stdlib.h> 48 49#include "exa_priv.h" 50 51#include "mipict.h" 52 53#if DEBUG_GLYPH_CACHE 54#define DBG_GLYPH_CACHE(a) ErrorF a 55#else 56#define DBG_GLYPH_CACHE(a) 57#endif 58 59/* Width of the pixmaps we use for the caches; this should be less than 60 * max texture size of the driver; this may need to actually come from 61 * the driver. 62 */ 63#define CACHE_PICTURE_WIDTH 1024 64 65/* Maximum number of glyphs we buffer on the stack before flushing 66 * rendering to the mask or destination surface. 67 */ 68#define GLYPH_BUFFER_SIZE 256 69 70typedef struct { 71 PicturePtr source; 72 ExaCompositeRectRec rects[GLYPH_BUFFER_SIZE]; 73 int count; 74} ExaGlyphBuffer, *ExaGlyphBufferPtr; 75 76typedef enum { 77 ExaGlyphSuccess, /* Glyph added to render buffer */ 78 ExaGlyphFail, /* out of memory, etc */ 79 ExaGlyphNeedFlush, /* would evict a glyph already in the buffer */ 80} ExaGlyphCacheResult; 81 82void 83exaGlyphsInit(ScreenPtr pScreen) 84{ 85 ExaScreenPriv(pScreen); 86 int i = 0; 87 88 memset(pExaScr->glyphCaches, 0, sizeof(pExaScr->glyphCaches)); 89 90 pExaScr->glyphCaches[i].format = PICT_a8; 91 pExaScr->glyphCaches[i].glyphWidth = pExaScr->glyphCaches[i].glyphHeight = 16; 92 i++; 93 pExaScr->glyphCaches[i].format = PICT_a8; 94 pExaScr->glyphCaches[i].glyphWidth = pExaScr->glyphCaches[i].glyphHeight = 32; 95 i++; 96 pExaScr->glyphCaches[i].format = PICT_a8r8g8b8; 97 pExaScr->glyphCaches[i].glyphWidth = pExaScr->glyphCaches[i].glyphHeight = 16; 98 i++; 99 pExaScr->glyphCaches[i].format = PICT_a8r8g8b8; 100 pExaScr->glyphCaches[i].glyphWidth = pExaScr->glyphCaches[i].glyphHeight = 32; 101 i++; 102 103 assert(i == EXA_NUM_GLYPH_CACHES); 104 105 for (i = 0; i < EXA_NUM_GLYPH_CACHES; i++) { 106 pExaScr->glyphCaches[i].columns = CACHE_PICTURE_WIDTH / pExaScr->glyphCaches[i].glyphWidth; 107 pExaScr->glyphCaches[i].size = 256; 108 pExaScr->glyphCaches[i].hashSize = 557; 109 } 110} 111 112static void 113exaUnrealizeGlyphCaches(ScreenPtr pScreen, 114 unsigned int format) 115{ 116 ExaScreenPriv(pScreen); 117 int i; 118 119 for (i = 0; i < EXA_NUM_GLYPH_CACHES; i++) { 120 ExaGlyphCachePtr cache = &pExaScr->glyphCaches[i]; 121 122 if (cache->format != format) 123 continue; 124 125 if (cache->picture) { 126 FreePicture ((pointer) cache->picture, (XID) 0); 127 cache->picture = NULL; 128 } 129 130 if (cache->hashEntries) { 131 xfree(cache->hashEntries); 132 cache->hashEntries = NULL; 133 } 134 135 if (cache->glyphs) { 136 xfree(cache->glyphs); 137 cache->glyphs = NULL; 138 } 139 cache->glyphCount = 0; 140 } 141} 142 143#define NeedsComponent(f) (PICT_FORMAT_A(f) != 0 && PICT_FORMAT_RGB(f) != 0) 144 145/* All caches for a single format share a single pixmap for glyph storage, 146 * allowing mixing glyphs of different sizes without paying a penalty 147 * for switching between source pixmaps. (Note that for a size of font 148 * right at the border between two sizes, we might be switching for almost 149 * every glyph.) 150 * 151 * This function allocates the storage pixmap, and then fills in the 152 * rest of the allocated structures for all caches with the given format. 153 */ 154static Bool 155exaRealizeGlyphCaches(ScreenPtr pScreen, 156 unsigned int format) 157{ 158 ExaScreenPriv(pScreen); 159 160 int depth = PIXMAN_FORMAT_DEPTH(format); 161 PictFormatPtr pPictFormat; 162 PixmapPtr pPixmap; 163 PicturePtr pPicture; 164 CARD32 component_alpha; 165 int height; 166 int i; 167 int error; 168 169 pPictFormat = PictureMatchFormat(pScreen, depth, format); 170 if (!pPictFormat) 171 return FALSE; 172 173 /* Compute the total vertical size needed for the format */ 174 175 height = 0; 176 for (i = 0; i < EXA_NUM_GLYPH_CACHES; i++) { 177 ExaGlyphCachePtr cache = &pExaScr->glyphCaches[i]; 178 int rows; 179 180 if (cache->format != format) 181 continue; 182 183 cache->yOffset = height; 184 185 rows = (cache->size + cache->columns - 1) / cache->columns; 186 height += rows * cache->glyphHeight; 187 } 188 189 /* Now allocate the pixmap and picture */ 190 191 pPixmap = (*pScreen->CreatePixmap) (pScreen, 192 CACHE_PICTURE_WIDTH, 193 height, depth, 0); 194 if (!pPixmap) 195 return FALSE; 196 197 component_alpha = NeedsComponent(pPictFormat->format); 198 pPicture = CreatePicture(0, &pPixmap->drawable, pPictFormat, 199 CPComponentAlpha, &component_alpha, serverClient, 200 &error); 201 202 (*pScreen->DestroyPixmap) (pPixmap); /* picture holds a refcount */ 203 204 if (!pPicture) 205 return FALSE; 206 207 /* And store the picture in all the caches for the format */ 208 209 for (i = 0; i < EXA_NUM_GLYPH_CACHES; i++) { 210 ExaGlyphCachePtr cache = &pExaScr->glyphCaches[i]; 211 int j; 212 213 if (cache->format != format) 214 continue; 215 216 cache->picture = pPicture; 217 cache->picture->refcnt++; 218 cache->hashEntries = xalloc(sizeof(int) * cache->hashSize); 219 cache->glyphs = xalloc(sizeof(ExaCachedGlyphRec) * cache->size); 220 cache->glyphCount = 0; 221 222 if (!cache->hashEntries || !cache->glyphs) 223 goto bail; 224 225 for (j = 0; j < cache->hashSize; j++) 226 cache->hashEntries[j] = -1; 227 228 cache->evictionPosition = rand() % cache->size; 229 } 230 231 /* Each cache references the picture individually */ 232 FreePicture ((pointer) pPicture, (XID) 0); 233 return TRUE; 234 235bail: 236 exaUnrealizeGlyphCaches(pScreen, format); 237 return FALSE; 238} 239 240void 241exaGlyphsFini (ScreenPtr pScreen) 242{ 243 ExaScreenPriv(pScreen); 244 int i; 245 246 for (i = 0; i < EXA_NUM_GLYPH_CACHES; i++) { 247 ExaGlyphCachePtr cache = &pExaScr->glyphCaches[i]; 248 249 if (cache->picture) 250 exaUnrealizeGlyphCaches(pScreen, cache->format); 251 } 252} 253 254static int 255exaGlyphCacheHashLookup(ExaGlyphCachePtr cache, 256 GlyphPtr pGlyph) 257{ 258 int slot; 259 260 slot = (*(CARD32 *) pGlyph->sha1) % cache->hashSize; 261 262 while (TRUE) { /* hash table can never be full */ 263 int entryPos = cache->hashEntries[slot]; 264 if (entryPos == -1) 265 return -1; 266 267 if (memcmp(pGlyph->sha1, cache->glyphs[entryPos].sha1, sizeof(pGlyph->sha1)) == 0){ 268 return entryPos; 269 } 270 271 slot--; 272 if (slot < 0) 273 slot = cache->hashSize - 1; 274 } 275} 276 277static void 278exaGlyphCacheHashInsert(ExaGlyphCachePtr cache, 279 GlyphPtr pGlyph, 280 int pos) 281{ 282 int slot; 283 284 memcpy(cache->glyphs[pos].sha1, pGlyph->sha1, sizeof(pGlyph->sha1)); 285 286 slot = (*(CARD32 *) pGlyph->sha1) % cache->hashSize; 287 288 while (TRUE) { /* hash table can never be full */ 289 if (cache->hashEntries[slot] == -1) { 290 cache->hashEntries[slot] = pos; 291 return; 292 } 293 294 slot--; 295 if (slot < 0) 296 slot = cache->hashSize - 1; 297 } 298} 299 300static void 301exaGlyphCacheHashRemove(ExaGlyphCachePtr cache, 302 int pos) 303{ 304 int slot; 305 int emptiedSlot = -1; 306 307 slot = (*(CARD32 *) cache->glyphs[pos].sha1) % cache->hashSize; 308 309 while (TRUE) { /* hash table can never be full */ 310 int entryPos = cache->hashEntries[slot]; 311 312 if (entryPos == -1) 313 return; 314 315 if (entryPos == pos) { 316 cache->hashEntries[slot] = -1; 317 emptiedSlot = slot; 318 } else if (emptiedSlot != -1) { 319 /* See if we can move this entry into the emptied slot, we can't 320 * do that if if entry would have hashed between the current position 321 * and the emptied slot. (taking wrapping into account). Bad positions 322 * are: 323 * 324 * | XXXXXXXXXX | 325 * i j 326 * 327 * |XXX XXXX| 328 * j i 329 * 330 * i - slot, j - emptiedSlot 331 * 332 * (Knuth 6.4R) 333 */ 334 335 int entrySlot = (*(CARD32 *) cache->glyphs[entryPos].sha1) % cache->hashSize; 336 337 if (!((entrySlot >= slot && entrySlot < emptiedSlot) || 338 (emptiedSlot < slot && (entrySlot < emptiedSlot || entrySlot >= slot)))) 339 { 340 cache->hashEntries[emptiedSlot] = entryPos; 341 cache->hashEntries[slot] = -1; 342 emptiedSlot = slot; 343 } 344 } 345 346 slot--; 347 if (slot < 0) 348 slot = cache->hashSize - 1; 349 } 350} 351 352#define CACHE_X(pos) (((pos) % cache->columns) * cache->glyphWidth) 353#define CACHE_Y(pos) (cache->yOffset + ((pos) / cache->columns) * cache->glyphHeight) 354 355/* The most efficient thing to way to upload the glyph to the screen 356 * is to use the UploadToScreen() driver hook; this allows us to 357 * pipeline glyph uploads and to avoid creating offscreen pixmaps for 358 * glyphs that we'll never use again. 359 */ 360static Bool 361exaGlyphCacheUploadGlyph(ScreenPtr pScreen, 362 ExaGlyphCachePtr cache, 363 int pos, 364 GlyphPtr pGlyph) 365{ 366 ExaScreenPriv(pScreen); 367 PicturePtr pGlyphPicture = GlyphPicture(pGlyph)[pScreen->myNum]; 368 PixmapPtr pGlyphPixmap = (PixmapPtr)pGlyphPicture->pDrawable; 369 ExaPixmapPriv(pGlyphPixmap); 370 PixmapPtr pCachePixmap = (PixmapPtr)cache->picture->pDrawable; 371 ExaMigrationRec pixmaps[1]; 372 373 if (!pExaScr->info->UploadToScreen || pExaScr->swappedOut || pExaPixmap->accel_blocked) 374 return FALSE; 375 376 /* If the glyph pixmap is already uploaded, no point in doing 377 * things this way */ 378 if (exaPixmapIsOffscreen(pGlyphPixmap)) 379 return FALSE; 380 381 /* UploadToScreen only works if bpp match */ 382 if (pGlyphPixmap->drawable.bitsPerPixel != pCachePixmap->drawable.bitsPerPixel) 383 return FALSE; 384 385 /* cache pixmap must be offscreen. */ 386 pixmaps[0].as_dst = TRUE; 387 pixmaps[0].as_src = FALSE; 388 pixmaps[0].pPix = pCachePixmap; 389 pixmaps[0].pReg = NULL; 390 exaDoMigration (pixmaps, 1, TRUE); 391 392 if (!exaPixmapIsOffscreen(pCachePixmap)) 393 return FALSE; 394 395 /* CACHE_{X,Y} are in pixmap coordinates, no need for cache{X,Y}off */ 396 if (!pExaScr->info->UploadToScreen(pCachePixmap, 397 CACHE_X(pos), 398 CACHE_Y(pos), 399 pGlyph->info.width, 400 pGlyph->info.height, 401 (char *)pExaPixmap->sys_ptr, 402 pExaPixmap->sys_pitch)) 403 return FALSE; 404 405 /* This pixmap should never be bound to a window, so no need to offset coordinates. */ 406 exaPixmapDirty (pCachePixmap, 407 CACHE_X(pos), 408 CACHE_Y(pos), 409 CACHE_X(pos) + pGlyph->info.width, 410 CACHE_Y(pos) + pGlyph->info.height); 411 412 return TRUE; 413} 414 415static ExaGlyphCacheResult 416exaGlyphCacheBufferGlyph(ScreenPtr pScreen, 417 ExaGlyphCachePtr cache, 418 ExaGlyphBufferPtr buffer, 419 GlyphPtr pGlyph, 420 int xGlyph, 421 int yGlyph) 422{ 423 ExaCompositeRectPtr rect; 424 int pos; 425 426 if (buffer->source && buffer->source != cache->picture) 427 return ExaGlyphNeedFlush; 428 429 if (!cache->picture) { 430 if (!exaRealizeGlyphCaches(pScreen, cache->format)) 431 return ExaGlyphFail; 432 } 433 434 DBG_GLYPH_CACHE(("(%d,%d,%s): buffering glyph %lx\n", 435 cache->glyphWidth, cache->glyphHeight, cache->format == PICT_a8 ? "A" : "ARGB", 436 (long)*(CARD32 *) pGlyph->sha1)); 437 438 pos = exaGlyphCacheHashLookup(cache, pGlyph); 439 if (pos != -1) { 440 DBG_GLYPH_CACHE((" found existing glyph at %d\n", pos)); 441 } else { 442 if (cache->glyphCount < cache->size) { 443 /* Space remaining; we fill from the start */ 444 pos = cache->glyphCount; 445 cache->glyphCount++; 446 DBG_GLYPH_CACHE((" storing glyph in free space at %d\n", pos)); 447 448 exaGlyphCacheHashInsert(cache, pGlyph, pos); 449 450 } else { 451 /* Need to evict an entry. We have to see if any glyphs 452 * already in the output buffer were at this position in 453 * the cache 454 */ 455 456 pos = cache->evictionPosition; 457 DBG_GLYPH_CACHE((" evicting glyph at %d\n", pos)); 458 if (buffer->count) { 459 int x, y; 460 int i; 461 462 x = CACHE_X(pos); 463 y = CACHE_Y(pos); 464 465 for (i = 0; i < buffer->count; i++) { 466 if (buffer->rects[i].xSrc == x && buffer->rects[i].ySrc == y) { 467 DBG_GLYPH_CACHE((" must flush buffer\n")); 468 return ExaGlyphNeedFlush; 469 } 470 } 471 } 472 473 /* OK, we're all set, swap in the new glyph */ 474 exaGlyphCacheHashRemove(cache, pos); 475 exaGlyphCacheHashInsert(cache, pGlyph, pos); 476 477 /* And pick a new eviction position */ 478 cache->evictionPosition = rand() % cache->size; 479 } 480 481 /* Now actually upload the glyph into the cache picture; if 482 * we can't do it with UploadToScreen (because the glyph is 483 * offscreen, etc), we fall back to CompositePicture. 484 */ 485 if (!exaGlyphCacheUploadGlyph(pScreen, cache, pos, pGlyph)) { 486 CompositePicture (PictOpSrc, 487 GlyphPicture(pGlyph)[pScreen->myNum], 488 None, 489 cache->picture, 490 0, 0, 491 0, 0, 492 CACHE_X(pos), 493 CACHE_Y(pos), 494 pGlyph->info.width, 495 pGlyph->info.height); 496 } 497 498 } 499 500 buffer->source = cache->picture; 501 502 rect = &buffer->rects[buffer->count]; 503 rect->xSrc = CACHE_X(pos); 504 rect->ySrc = CACHE_Y(pos); 505 rect->xDst = xGlyph - pGlyph->info.x; 506 rect->yDst = yGlyph - pGlyph->info.y; 507 rect->width = pGlyph->info.width; 508 rect->height = pGlyph->info.height; 509 510 buffer->count++; 511 512 return ExaGlyphSuccess; 513} 514 515#undef CACHE_X 516#undef CACHE_Y 517 518static ExaGlyphCacheResult 519exaBufferGlyph(ScreenPtr pScreen, 520 ExaGlyphBufferPtr buffer, 521 GlyphPtr pGlyph, 522 int xGlyph, 523 int yGlyph) 524{ 525 ExaScreenPriv(pScreen); 526 unsigned int format = (GlyphPicture(pGlyph)[pScreen->myNum])->format; 527 int width = pGlyph->info.width; 528 int height = pGlyph->info.height; 529 ExaCompositeRectPtr rect; 530 PicturePtr source; 531 int i; 532 533 if (buffer->count == GLYPH_BUFFER_SIZE) 534 return ExaGlyphNeedFlush; 535 536 if (PICT_FORMAT_BPP(format) == 1) 537 format = PICT_a8; 538 539 for (i = 0; i < EXA_NUM_GLYPH_CACHES; i++) { 540 ExaGlyphCachePtr cache = &pExaScr->glyphCaches[i]; 541 542 if (format == cache->format && 543 width <= cache->glyphWidth && 544 height <= cache->glyphHeight) { 545 ExaGlyphCacheResult result = exaGlyphCacheBufferGlyph(pScreen, &pExaScr->glyphCaches[i], 546 buffer, 547 pGlyph, xGlyph, yGlyph); 548 switch (result) { 549 case ExaGlyphFail: 550 break; 551 case ExaGlyphSuccess: 552 case ExaGlyphNeedFlush: 553 return result; 554 } 555 } 556 } 557 558 /* Couldn't find the glyph in the cache, use the glyph picture directly */ 559 560 source = GlyphPicture(pGlyph)[pScreen->myNum]; 561 if (buffer->source && buffer->source != source) 562 return ExaGlyphNeedFlush; 563 564 buffer->source = source; 565 566 rect = &buffer->rects[buffer->count]; 567 rect->xSrc = 0; 568 rect->ySrc = 0; 569 rect->xDst = xGlyph - pGlyph->info.x; 570 rect->yDst = yGlyph - pGlyph->info.y; 571 rect->width = pGlyph->info.width; 572 rect->height = pGlyph->info.height; 573 574 buffer->count++; 575 576 return ExaGlyphSuccess; 577} 578 579static void 580exaGlyphsToMask(PicturePtr pMask, 581 ExaGlyphBufferPtr buffer) 582{ 583 exaCompositeRects(PictOpAdd, buffer->source, pMask, 584 buffer->count, buffer->rects); 585 586 buffer->count = 0; 587 buffer->source = NULL; 588} 589 590static void 591exaGlyphsToDst(CARD8 op, 592 PicturePtr pSrc, 593 PicturePtr pDst, 594 ExaGlyphBufferPtr buffer, 595 INT16 xSrc, 596 INT16 ySrc, 597 INT16 xDst, 598 INT16 yDst) 599{ 600 int i; 601 602 for (i = 0; i < buffer->count; i++) { 603 ExaCompositeRectPtr rect = &buffer->rects[i]; 604 605 CompositePicture (op, 606 pSrc, 607 buffer->source, 608 pDst, 609 xSrc + rect->xDst - xDst, 610 ySrc + rect->yDst - yDst, 611 rect->xSrc, 612 rect->ySrc, 613 rect->xDst, 614 rect->yDst, 615 rect->width, 616 rect->height); 617 } 618 619 buffer->count = 0; 620 buffer->source = NULL; 621} 622 623/* Cut and paste from render/glyph.c - probably should export it instead */ 624static void 625GlyphExtents (int nlist, 626 GlyphListPtr list, 627 GlyphPtr *glyphs, 628 BoxPtr extents) 629{ 630 int x1, x2, y1, y2; 631 int n; 632 GlyphPtr glyph; 633 int x, y; 634 635 x = 0; 636 y = 0; 637 extents->x1 = MAXSHORT; 638 extents->x2 = MINSHORT; 639 extents->y1 = MAXSHORT; 640 extents->y2 = MINSHORT; 641 while (nlist--) 642 { 643 x += list->xOff; 644 y += list->yOff; 645 n = list->len; 646 list++; 647 while (n--) 648 { 649 glyph = *glyphs++; 650 x1 = x - glyph->info.x; 651 if (x1 < MINSHORT) 652 x1 = MINSHORT; 653 y1 = y - glyph->info.y; 654 if (y1 < MINSHORT) 655 y1 = MINSHORT; 656 x2 = x1 + glyph->info.width; 657 if (x2 > MAXSHORT) 658 x2 = MAXSHORT; 659 y2 = y1 + glyph->info.height; 660 if (y2 > MAXSHORT) 661 y2 = MAXSHORT; 662 if (x1 < extents->x1) 663 extents->x1 = x1; 664 if (x2 > extents->x2) 665 extents->x2 = x2; 666 if (y1 < extents->y1) 667 extents->y1 = y1; 668 if (y2 > extents->y2) 669 extents->y2 = y2; 670 x += glyph->info.xOff; 671 y += glyph->info.yOff; 672 } 673 } 674} 675 676/** 677 * Returns TRUE if the glyphs in the lists intersect. Only checks based on 678 * bounding box, which appears to be good enough to catch most cases at least. 679 */ 680static Bool 681exaGlyphsIntersect(int nlist, GlyphListPtr list, GlyphPtr *glyphs) 682{ 683 int x1, x2, y1, y2; 684 int n; 685 GlyphPtr glyph; 686 int x, y; 687 BoxRec extents; 688 Bool first = TRUE; 689 690 x = 0; 691 y = 0; 692 while (nlist--) { 693 x += list->xOff; 694 y += list->yOff; 695 n = list->len; 696 list++; 697 while (n--) { 698 glyph = *glyphs++; 699 700 if (glyph->info.width == 0 || glyph->info.height == 0) { 701 x += glyph->info.xOff; 702 y += glyph->info.yOff; 703 continue; 704 } 705 706 x1 = x - glyph->info.x; 707 if (x1 < MINSHORT) 708 x1 = MINSHORT; 709 y1 = y - glyph->info.y; 710 if (y1 < MINSHORT) 711 y1 = MINSHORT; 712 x2 = x1 + glyph->info.width; 713 if (x2 > MAXSHORT) 714 x2 = MAXSHORT; 715 y2 = y1 + glyph->info.height; 716 if (y2 > MAXSHORT) 717 y2 = MAXSHORT; 718 719 if (first) { 720 extents.x1 = x1; 721 extents.y1 = y1; 722 extents.x2 = x2; 723 extents.y2 = y2; 724 first = FALSE; 725 } else { 726 if (x1 < extents.x2 && x2 > extents.x1 && 727 y1 < extents.y2 && y2 > extents.y1) 728 { 729 return TRUE; 730 } 731 732 if (x1 < extents.x1) 733 extents.x1 = x1; 734 if (x2 > extents.x2) 735 extents.x2 = x2; 736 if (y1 < extents.y1) 737 extents.y1 = y1; 738 if (y2 > extents.y2) 739 extents.y2 = y2; 740 } 741 x += glyph->info.xOff; 742 y += glyph->info.yOff; 743 } 744 } 745 746 return FALSE; 747} 748 749void 750exaGlyphs (CARD8 op, 751 PicturePtr pSrc, 752 PicturePtr pDst, 753 PictFormatPtr maskFormat, 754 INT16 xSrc, 755 INT16 ySrc, 756 int nlist, 757 GlyphListPtr list, 758 GlyphPtr *glyphs) 759{ 760 PicturePtr pPicture; 761 PixmapPtr pMaskPixmap = 0; 762 PicturePtr pMask; 763 ScreenPtr pScreen = pDst->pDrawable->pScreen; 764 int width = 0, height = 0; 765 int x, y; 766 int xDst = list->xOff, yDst = list->yOff; 767 int n; 768 GlyphPtr glyph; 769 int error; 770 BoxRec extents = {0, 0, 0, 0}; 771 CARD32 component_alpha; 772 ExaGlyphBuffer buffer; 773 774 /* If we don't have a mask format but all the glyphs have the same format 775 * and don't intersect, use the glyph format as mask format for the full 776 * benefits of the glyph cache. 777 */ 778 if (!maskFormat) { 779 Bool sameFormat = TRUE; 780 int i; 781 782 maskFormat = list[0].format; 783 784 for (i = 0; i < nlist; i++) { 785 if (maskFormat->format != list[i].format->format) { 786 sameFormat = FALSE; 787 break; 788 } 789 } 790 791 if (!sameFormat || (maskFormat->depth != 1 && 792 exaGlyphsIntersect(nlist, list, glyphs))) { 793 maskFormat = NULL; 794 } 795 } 796 797 if (maskFormat) 798 { 799 GCPtr pGC; 800 xRectangle rect; 801 802 GlyphExtents (nlist, list, glyphs, &extents); 803 804 if (extents.x2 <= extents.x1 || extents.y2 <= extents.y1) 805 return; 806 width = extents.x2 - extents.x1; 807 height = extents.y2 - extents.y1; 808 809 if (maskFormat->depth == 1) { 810 PictFormatPtr a8Format = PictureMatchFormat (pScreen, 8, PICT_a8); 811 812 if (a8Format) 813 maskFormat = a8Format; 814 } 815 816 pMaskPixmap = (*pScreen->CreatePixmap) (pScreen, width, height, 817 maskFormat->depth, 818 CREATE_PIXMAP_USAGE_SCRATCH); 819 if (!pMaskPixmap) 820 return; 821 component_alpha = NeedsComponent(maskFormat->format); 822 pMask = CreatePicture (0, &pMaskPixmap->drawable, 823 maskFormat, CPComponentAlpha, &component_alpha, 824 serverClient, &error); 825 if (!pMask) 826 { 827 (*pScreen->DestroyPixmap) (pMaskPixmap); 828 return; 829 } 830 pGC = GetScratchGC (pMaskPixmap->drawable.depth, pScreen); 831 ValidateGC (&pMaskPixmap->drawable, pGC); 832 rect.x = 0; 833 rect.y = 0; 834 rect.width = width; 835 rect.height = height; 836 (*pGC->ops->PolyFillRect) (&pMaskPixmap->drawable, pGC, 1, &rect); 837 FreeScratchGC (pGC); 838 x = -extents.x1; 839 y = -extents.y1; 840 } 841 else 842 { 843 pMask = pDst; 844 x = 0; 845 y = 0; 846 } 847 buffer.count = 0; 848 buffer.source = NULL; 849 while (nlist--) 850 { 851 x += list->xOff; 852 y += list->yOff; 853 n = list->len; 854 while (n--) 855 { 856 glyph = *glyphs++; 857 pPicture = GlyphPicture (glyph)[pScreen->myNum]; 858 859 if (glyph->info.width > 0 && glyph->info.height > 0 && 860 exaBufferGlyph(pScreen, &buffer, glyph, x, y) == ExaGlyphNeedFlush) 861 { 862 if (maskFormat) 863 exaGlyphsToMask(pMask, &buffer); 864 else 865 exaGlyphsToDst(op, pSrc, pDst, &buffer, 866 xSrc, ySrc, xDst, yDst); 867 868 exaBufferGlyph(pScreen, &buffer, glyph, x, y); 869 } 870 871 x += glyph->info.xOff; 872 y += glyph->info.yOff; 873 } 874 list++; 875 } 876 877 if (buffer.count) { 878 if (maskFormat) 879 exaGlyphsToMask(pMask, &buffer); 880 else 881 exaGlyphsToDst(op, pSrc, pDst, &buffer, 882 xSrc, ySrc, xDst, yDst); 883 } 884 885 if (maskFormat) 886 { 887 x = extents.x1; 888 y = extents.y1; 889 CompositePicture (op, 890 pSrc, 891 pMask, 892 pDst, 893 xSrc + x - xDst, 894 ySrc + y - yDst, 895 0, 0, 896 x, y, 897 width, height); 898 FreePicture ((pointer) pMask, (XID) 0); 899 (*pScreen->DestroyPixmap) (pMaskPixmap); 900 } 901} 902