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