1d514b0f3Smrg/* 2d514b0f3Smrg * Copyright © 2010 Intel Corporation 3d514b0f3Smrg * Partly based on code Copyright © 2008 Red Hat, Inc. 4d514b0f3Smrg * Partly based on code Copyright © 2000 SuSE, Inc. 5d514b0f3Smrg * 6d514b0f3Smrg * Permission to use, copy, modify, distribute, and sell this software and its 7d514b0f3Smrg * documentation for any purpose is hereby granted without fee, provided that 8d514b0f3Smrg * the above copyright notice appear in all copies and that both that 9d514b0f3Smrg * copyright notice and this permission notice appear in supporting 10d514b0f3Smrg * documentation, and that the name of Intel not be used in advertising or 11d514b0f3Smrg * publicity pertaining to distribution of the software without specific, 12d514b0f3Smrg * written prior permission. Intel makes no representations about the 13d514b0f3Smrg * suitability of this software for any purpose. It is provided "as is" 14d514b0f3Smrg * without express or implied warranty. 15d514b0f3Smrg * 16d514b0f3Smrg * INTEL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL 17d514b0f3Smrg * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL INTEL 18d514b0f3Smrg * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 19d514b0f3Smrg * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 20d514b0f3Smrg * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 21d514b0f3Smrg * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 22d514b0f3Smrg * 23d514b0f3Smrg * Permission to use, copy, modify, distribute, and sell this software and its 24d514b0f3Smrg * documentation for any purpose is hereby granted without fee, provided that 25d514b0f3Smrg * the above copyright notice appear in all copies and that both that 26d514b0f3Smrg * copyright notice and this permission notice appear in supporting 27d514b0f3Smrg * documentation, and that the name of Red Hat not be used in advertising or 28d514b0f3Smrg * publicity pertaining to distribution of the software without specific, 29d514b0f3Smrg * written prior permission. Red Hat makes no representations about the 30d514b0f3Smrg * suitability of this software for any purpose. It is provided "as is" 31d514b0f3Smrg * without express or implied warranty. 32d514b0f3Smrg * 33d514b0f3Smrg * Red Hat DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL 34d514b0f3Smrg * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL Red Hat 35d514b0f3Smrg * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 36d514b0f3Smrg * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 37d514b0f3Smrg * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 38d514b0f3Smrg * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 39d514b0f3Smrg * 40d514b0f3Smrg * Permission to use, copy, modify, distribute, and sell this software and its 41d514b0f3Smrg * documentation for any purpose is hereby granted without fee, provided that 42d514b0f3Smrg * the above copyright notice appear in all copies and that both that 43d514b0f3Smrg * copyright notice and this permission notice appear in supporting 44d514b0f3Smrg * documentation, and that the name of SuSE not be used in advertising or 45d514b0f3Smrg * publicity pertaining to distribution of the software without specific, 46d514b0f3Smrg * written prior permission. SuSE makes no representations about the 47d514b0f3Smrg * suitability of this software for any purpose. It is provided "as is" 48d514b0f3Smrg * without express or implied warranty. 49d514b0f3Smrg * 50d514b0f3Smrg * SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL 51d514b0f3Smrg * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE 52d514b0f3Smrg * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 53d514b0f3Smrg * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 54d514b0f3Smrg * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 55d514b0f3Smrg * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 56d514b0f3Smrg * 57d514b0f3Smrg * Author: Chris Wilson <chris@chris-wilson.co.uk> 58d514b0f3Smrg * Based on code by: Keith Packard <keithp@keithp.com> and Owen Taylor <otaylor@fishsoup.net> 59d514b0f3Smrg */ 60d514b0f3Smrg 61d514b0f3Smrg#ifdef HAVE_DIX_CONFIG_H 62d514b0f3Smrg#include <dix-config.h> 63d514b0f3Smrg#endif 64d514b0f3Smrg 65d514b0f3Smrg#include <stdlib.h> 66d514b0f3Smrg 67d514b0f3Smrg#include "uxa-priv.h" 68d514b0f3Smrg 69d514b0f3Smrg#include "mipict.h" 70d514b0f3Smrg 71d514b0f3Smrg/* Width of the pixmaps we use for the caches; this should be less than 72d514b0f3Smrg * max texture size of the driver; this may need to actually come from 73d514b0f3Smrg * the driver. 74d514b0f3Smrg */ 75d514b0f3Smrg#define CACHE_PICTURE_SIZE 1024 76d514b0f3Smrg#define GLYPH_MIN_SIZE 8 77d514b0f3Smrg#define GLYPH_MAX_SIZE 64 78d514b0f3Smrg#define GLYPH_CACHE_SIZE (CACHE_PICTURE_SIZE * CACHE_PICTURE_SIZE / (GLYPH_MIN_SIZE * GLYPH_MIN_SIZE)) 79d514b0f3Smrg 80d514b0f3Smrgstruct uxa_glyph { 81d514b0f3Smrg uxa_glyph_cache_t *cache; 82d514b0f3Smrg uint16_t x, y; 83d514b0f3Smrg uint16_t size, pos; 84d514b0f3Smrg}; 85d514b0f3Smrg 86d514b0f3Smrg#if HAS_DEVPRIVATEKEYREC 87d514b0f3Smrgstatic DevPrivateKeyRec uxa_glyph_key; 88d514b0f3Smrg#else 89d514b0f3Smrgstatic int uxa_glyph_key; 90d514b0f3Smrg#endif 91d514b0f3Smrg 92d514b0f3Smrgstatic inline struct uxa_glyph *uxa_glyph_get_private(GlyphPtr glyph) 93d514b0f3Smrg{ 94d514b0f3Smrg#if HAS_DEVPRIVATEKEYREC 95d514b0f3Smrg return dixGetPrivate(&glyph->devPrivates, &uxa_glyph_key); 96d514b0f3Smrg#else 97d514b0f3Smrg return dixLookupPrivate(&glyph->devPrivates, &uxa_glyph_key); 98d514b0f3Smrg#endif 99d514b0f3Smrg} 100d514b0f3Smrg 101d514b0f3Smrgstatic inline void uxa_glyph_set_private(GlyphPtr glyph, struct uxa_glyph *priv) 102d514b0f3Smrg{ 103d514b0f3Smrg dixSetPrivate(&glyph->devPrivates, &uxa_glyph_key, priv); 104d514b0f3Smrg} 105d514b0f3Smrg 106d514b0f3Smrg#define NeedsComponent(f) (PICT_FORMAT_A(f) != 0 && PICT_FORMAT_RGB(f) != 0) 107d514b0f3Smrg 108d514b0f3Smrgstatic void uxa_unrealize_glyph_caches(ScreenPtr pScreen) 109d514b0f3Smrg{ 110d514b0f3Smrg uxa_screen_t *uxa_screen = uxa_get_screen(pScreen); 111d514b0f3Smrg int i; 112d514b0f3Smrg 113d514b0f3Smrg for (i = 0; i < UXA_NUM_GLYPH_CACHE_FORMATS; i++) { 114d514b0f3Smrg uxa_glyph_cache_t *cache = &uxa_screen->glyphCaches[i]; 115d514b0f3Smrg 116d514b0f3Smrg if (cache->picture) 117d514b0f3Smrg FreePicture(cache->picture, 0); 118d514b0f3Smrg 119d514b0f3Smrg if (cache->glyphs) 120d514b0f3Smrg free(cache->glyphs); 121d514b0f3Smrg } 122d514b0f3Smrg} 123d514b0f3Smrg 124d514b0f3Smrgvoid uxa_glyphs_fini(ScreenPtr pScreen) 125d514b0f3Smrg{ 126d514b0f3Smrg uxa_unrealize_glyph_caches(pScreen); 127d514b0f3Smrg} 128d514b0f3Smrg 129d514b0f3Smrg/* All caches for a single format share a single pixmap for glyph storage, 130d514b0f3Smrg * allowing mixing glyphs of different sizes without paying a penalty 131d514b0f3Smrg * for switching between source pixmaps. (Note that for a size of font 132d514b0f3Smrg * right at the border between two sizes, we might be switching for almost 133d514b0f3Smrg * every glyph.) 134d514b0f3Smrg * 135d514b0f3Smrg * This function allocates the storage pixmap, and then fills in the 136d514b0f3Smrg * rest of the allocated structures for all caches with the given format. 137d514b0f3Smrg */ 138d514b0f3Smrgstatic Bool uxa_realize_glyph_caches(ScreenPtr pScreen) 139d514b0f3Smrg{ 140d514b0f3Smrg uxa_screen_t *uxa_screen = uxa_get_screen(pScreen); 141d514b0f3Smrg unsigned int formats[] = { 142d514b0f3Smrg PIXMAN_a8, 143d514b0f3Smrg PIXMAN_a8r8g8b8, 144d514b0f3Smrg }; 145d514b0f3Smrg int i; 146d514b0f3Smrg 147d514b0f3Smrg memset(uxa_screen->glyphCaches, 0, sizeof(uxa_screen->glyphCaches)); 148d514b0f3Smrg 149d514b0f3Smrg for (i = 0; i < sizeof(formats)/sizeof(formats[0]); i++) { 150d514b0f3Smrg uxa_glyph_cache_t *cache = &uxa_screen->glyphCaches[i]; 151d514b0f3Smrg PixmapPtr pixmap; 152d514b0f3Smrg PicturePtr picture; 153d514b0f3Smrg CARD32 component_alpha; 154d514b0f3Smrg int depth = PIXMAN_FORMAT_DEPTH(formats[i]); 155d514b0f3Smrg int error; 156d514b0f3Smrg PictFormatPtr pPictFormat = PictureMatchFormat(pScreen, depth, formats[i]); 157d514b0f3Smrg if (!pPictFormat) 158d514b0f3Smrg goto bail; 159d514b0f3Smrg 160d514b0f3Smrg /* Now allocate the pixmap and picture */ 161d514b0f3Smrg pixmap = pScreen->CreatePixmap(pScreen, 162d514b0f3Smrg CACHE_PICTURE_SIZE, CACHE_PICTURE_SIZE, depth, 163d514b0f3Smrg 0 /* INTEL_CREATE_PIXMAP_TILING_X -- FIXME */); 164d514b0f3Smrg if (!pixmap) 165d514b0f3Smrg goto bail; 166d514b0f3Smrg#if 0 167d514b0f3Smrg assert (uxa_pixmap_is_offscreen(pixmap)); 168d514b0f3Smrg#endif 169d514b0f3Smrg 170d514b0f3Smrg component_alpha = NeedsComponent(pPictFormat->format); 171d514b0f3Smrg picture = CreatePicture(0, &pixmap->drawable, pPictFormat, 172d514b0f3Smrg CPComponentAlpha, &component_alpha, 173d514b0f3Smrg serverClient, &error); 174d514b0f3Smrg 175d514b0f3Smrg pScreen->DestroyPixmap(pixmap); 176d514b0f3Smrg 177d514b0f3Smrg if (!picture) 178d514b0f3Smrg goto bail; 179d514b0f3Smrg 180d514b0f3Smrg ValidatePicture(picture); 181d514b0f3Smrg 182d514b0f3Smrg cache->picture = picture; 183d514b0f3Smrg cache->glyphs = calloc(sizeof(GlyphPtr), GLYPH_CACHE_SIZE); 184d514b0f3Smrg if (!cache->glyphs) 185d514b0f3Smrg goto bail; 186d514b0f3Smrg 187d514b0f3Smrg cache->evict = rand() % GLYPH_CACHE_SIZE; 188d514b0f3Smrg } 189d514b0f3Smrg assert(i == UXA_NUM_GLYPH_CACHE_FORMATS); 190d514b0f3Smrg 191d514b0f3Smrg return TRUE; 192d514b0f3Smrg 193d514b0f3Smrgbail: 194d514b0f3Smrg uxa_unrealize_glyph_caches(pScreen); 195d514b0f3Smrg return FALSE; 196d514b0f3Smrg} 197d514b0f3Smrg 198d514b0f3Smrg 199d514b0f3SmrgBool uxa_glyphs_init(ScreenPtr pScreen) 200d514b0f3Smrg{ 201d514b0f3Smrg#if HAS_DIXREGISTERPRIVATEKEY 202d514b0f3Smrg if (!dixRegisterPrivateKey(&uxa_glyph_key, PRIVATE_GLYPH, 0)) 203d514b0f3Smrg return FALSE; 204d514b0f3Smrg#else 205d514b0f3Smrg if (!dixRequestPrivate(&uxa_glyph_key, 0)) 206d514b0f3Smrg return FALSE; 207d514b0f3Smrg#endif 208d514b0f3Smrg 209d514b0f3Smrg if (!uxa_realize_glyph_caches(pScreen)) 210d514b0f3Smrg return FALSE; 211d514b0f3Smrg 212d514b0f3Smrg return TRUE; 213d514b0f3Smrg} 214d514b0f3Smrg 215d514b0f3Smrg/* The most efficient thing to way to upload the glyph to the screen 216d514b0f3Smrg * is to use CopyArea; uxa pixmaps are always offscreen. 217d514b0f3Smrg */ 218d514b0f3Smrgstatic void 219d514b0f3Smrguxa_glyph_cache_upload_glyph(ScreenPtr screen, 220d514b0f3Smrg uxa_glyph_cache_t * cache, 221d514b0f3Smrg GlyphPtr glyph, 222d514b0f3Smrg int x, int y) 223d514b0f3Smrg{ 224d514b0f3Smrg PicturePtr pGlyphPicture = GetGlyphPicture(glyph, screen); 225d514b0f3Smrg PixmapPtr pGlyphPixmap = (PixmapPtr) pGlyphPicture->pDrawable; 226d514b0f3Smrg PixmapPtr pCachePixmap = (PixmapPtr) cache->picture->pDrawable; 227d514b0f3Smrg PixmapPtr scratch; 228d514b0f3Smrg GCPtr gc; 229d514b0f3Smrg 230d514b0f3Smrg gc = GetScratchGC(pCachePixmap->drawable.depth, screen); 231d514b0f3Smrg if (!gc) 232d514b0f3Smrg return; 233d514b0f3Smrg 234d514b0f3Smrg ValidateGC(&pCachePixmap->drawable, gc); 235d514b0f3Smrg 236d514b0f3Smrg scratch = pGlyphPixmap; 237d514b0f3Smrg /* Create a temporary bo to stream the updates to the cache */ 238d514b0f3Smrg if (pGlyphPixmap->drawable.depth != pCachePixmap->drawable.depth || 239d514b0f3Smrg !uxa_pixmap_is_offscreen(scratch)) { 240d514b0f3Smrg scratch = screen->CreatePixmap(screen, 241d514b0f3Smrg glyph->info.width, 242d514b0f3Smrg glyph->info.height, 243d514b0f3Smrg pCachePixmap->drawable.depth, 244d514b0f3Smrg UXA_CREATE_PIXMAP_FOR_MAP); 245d514b0f3Smrg if (scratch) { 246d514b0f3Smrg if (pGlyphPixmap->drawable.depth != pCachePixmap->drawable.depth) { 247d514b0f3Smrg PicturePtr picture; 248d514b0f3Smrg int error; 249d514b0f3Smrg 250d514b0f3Smrg picture = CreatePicture(0, &scratch->drawable, 251d514b0f3Smrg PictureMatchFormat(screen, 252d514b0f3Smrg pCachePixmap->drawable.depth, 253d514b0f3Smrg cache->picture->format), 254d514b0f3Smrg 0, NULL, 255d514b0f3Smrg serverClient, &error); 256d514b0f3Smrg if (picture) { 257d514b0f3Smrg ValidatePicture(picture); 258d514b0f3Smrg uxa_composite(PictOpSrc, pGlyphPicture, NULL, picture, 259d514b0f3Smrg 0, 0, 260d514b0f3Smrg 0, 0, 261d514b0f3Smrg 0, 0, 262d514b0f3Smrg glyph->info.width, glyph->info.height); 263d514b0f3Smrg FreePicture(picture, 0); 264d514b0f3Smrg } 265d514b0f3Smrg } else { 266d514b0f3Smrg uxa_copy_area(&pGlyphPixmap->drawable, 267d514b0f3Smrg &scratch->drawable, 268d514b0f3Smrg gc, 269d514b0f3Smrg 0, 0, 270d514b0f3Smrg glyph->info.width, glyph->info.height, 271d514b0f3Smrg 0, 0); 272d514b0f3Smrg } 273d514b0f3Smrg } else { 274d514b0f3Smrg scratch = pGlyphPixmap; 275d514b0f3Smrg } 276d514b0f3Smrg } 277d514b0f3Smrg 278d514b0f3Smrg uxa_copy_area(&scratch->drawable, &pCachePixmap->drawable, gc, 279d514b0f3Smrg 0, 0, 280d514b0f3Smrg glyph->info.width, glyph->info.height, 281d514b0f3Smrg x, y); 282d514b0f3Smrg 283d514b0f3Smrg if (scratch != pGlyphPixmap) 284d514b0f3Smrg screen->DestroyPixmap(scratch); 285d514b0f3Smrg 286d514b0f3Smrg FreeScratchGC(gc); 287d514b0f3Smrg} 288d514b0f3Smrg 289d514b0f3Smrgvoid 290d514b0f3Smrguxa_glyph_unrealize(ScreenPtr pScreen, 291d514b0f3Smrg GlyphPtr pGlyph) 292d514b0f3Smrg{ 293d514b0f3Smrg struct uxa_glyph *priv; 294d514b0f3Smrg 295d514b0f3Smrg priv = uxa_glyph_get_private(pGlyph); 296d514b0f3Smrg if (priv == NULL) 297d514b0f3Smrg return; 298d514b0f3Smrg 299d514b0f3Smrg priv->cache->glyphs[priv->pos] = NULL; 300d514b0f3Smrg 301d514b0f3Smrg uxa_glyph_set_private(pGlyph, NULL); 302d514b0f3Smrg free(priv); 303d514b0f3Smrg} 304d514b0f3Smrg 305d514b0f3Smrg/* Cut and paste from render/glyph.c - probably should export it instead */ 306d514b0f3Smrgstatic void 307d514b0f3Smrguxa_glyph_extents(int nlist, 308d514b0f3Smrg GlyphListPtr list, GlyphPtr * glyphs, BoxPtr extents) 309d514b0f3Smrg{ 310d514b0f3Smrg int x1, x2, y1, y2; 311d514b0f3Smrg int x, y, n; 312d514b0f3Smrg 313d514b0f3Smrg x1 = y1 = MAXSHORT; 314d514b0f3Smrg x2 = y2 = MINSHORT; 315d514b0f3Smrg x = y = 0; 316d514b0f3Smrg while (nlist--) { 317d514b0f3Smrg x += list->xOff; 318d514b0f3Smrg y += list->yOff; 319d514b0f3Smrg n = list->len; 320d514b0f3Smrg list++; 321d514b0f3Smrg while (n--) { 322d514b0f3Smrg GlyphPtr glyph = *glyphs++; 323d514b0f3Smrg int v; 324d514b0f3Smrg 325d514b0f3Smrg v = x - glyph->info.x; 326d514b0f3Smrg if (v < x1) 327d514b0f3Smrg x1 = v; 328d514b0f3Smrg v += glyph->info.width; 329d514b0f3Smrg if (v > x2) 330d514b0f3Smrg x2 = v; 331d514b0f3Smrg 332d514b0f3Smrg v = y - glyph->info.y; 333d514b0f3Smrg if (v < y1) 334d514b0f3Smrg y1 = v; 335d514b0f3Smrg v += glyph->info.height; 336d514b0f3Smrg if (v > y2) 337d514b0f3Smrg y2 = v; 338d514b0f3Smrg 339d514b0f3Smrg x += glyph->info.xOff; 340d514b0f3Smrg y += glyph->info.yOff; 341d514b0f3Smrg } 342d514b0f3Smrg } 343d514b0f3Smrg 344d514b0f3Smrg extents->x1 = x1 < MINSHORT ? MINSHORT : x1; 345d514b0f3Smrg extents->x2 = x2 > MAXSHORT ? MAXSHORT : x2; 346d514b0f3Smrg extents->y1 = y1 < MINSHORT ? MINSHORT : y1; 347d514b0f3Smrg extents->y2 = y2 > MAXSHORT ? MAXSHORT : y2; 348d514b0f3Smrg} 349d514b0f3Smrg 350d514b0f3Smrg/** 351d514b0f3Smrg * Returns TRUE if the glyphs in the lists intersect. Only checks based on 352d514b0f3Smrg * bounding box, which appears to be good enough to catch most cases at least. 353d514b0f3Smrg */ 354d514b0f3Smrgstatic Bool 355d514b0f3Smrguxa_glyphs_intersect(int nlist, GlyphListPtr list, GlyphPtr * glyphs) 356d514b0f3Smrg{ 357d514b0f3Smrg int x1, x2, y1, y2; 358d514b0f3Smrg int n; 359d514b0f3Smrg int x, y; 360d514b0f3Smrg BoxRec extents; 361d514b0f3Smrg Bool first = TRUE; 362d514b0f3Smrg 363d514b0f3Smrg x = 0; 364d514b0f3Smrg y = 0; 365d514b0f3Smrg extents.x1 = 0; 366d514b0f3Smrg extents.y1 = 0; 367d514b0f3Smrg extents.x2 = 0; 368d514b0f3Smrg extents.y2 = 0; 369d514b0f3Smrg while (nlist--) { 370d514b0f3Smrg x += list->xOff; 371d514b0f3Smrg y += list->yOff; 372d514b0f3Smrg n = list->len; 373d514b0f3Smrg list++; 374d514b0f3Smrg while (n--) { 375d514b0f3Smrg GlyphPtr glyph = *glyphs++; 376d514b0f3Smrg 377d514b0f3Smrg if (glyph->info.width == 0 || glyph->info.height == 0) { 378d514b0f3Smrg x += glyph->info.xOff; 379d514b0f3Smrg y += glyph->info.yOff; 380d514b0f3Smrg continue; 381d514b0f3Smrg } 382d514b0f3Smrg 383d514b0f3Smrg x1 = x - glyph->info.x; 384d514b0f3Smrg if (x1 < MINSHORT) 385d514b0f3Smrg x1 = MINSHORT; 386d514b0f3Smrg y1 = y - glyph->info.y; 387d514b0f3Smrg if (y1 < MINSHORT) 388d514b0f3Smrg y1 = MINSHORT; 389d514b0f3Smrg x2 = x1 + glyph->info.width; 390d514b0f3Smrg if (x2 > MAXSHORT) 391d514b0f3Smrg x2 = MAXSHORT; 392d514b0f3Smrg y2 = y1 + glyph->info.height; 393d514b0f3Smrg if (y2 > MAXSHORT) 394d514b0f3Smrg y2 = MAXSHORT; 395d514b0f3Smrg 396d514b0f3Smrg if (first) { 397d514b0f3Smrg extents.x1 = x1; 398d514b0f3Smrg extents.y1 = y1; 399d514b0f3Smrg extents.x2 = x2; 400d514b0f3Smrg extents.y2 = y2; 401d514b0f3Smrg first = FALSE; 402d514b0f3Smrg } else { 403d514b0f3Smrg if (x1 < extents.x2 && x2 > extents.x1 && 404d514b0f3Smrg y1 < extents.y2 && y2 > extents.y1) { 405d514b0f3Smrg return TRUE; 406d514b0f3Smrg } 407d514b0f3Smrg 408d514b0f3Smrg if (x1 < extents.x1) 409d514b0f3Smrg extents.x1 = x1; 410d514b0f3Smrg if (x2 > extents.x2) 411d514b0f3Smrg extents.x2 = x2; 412d514b0f3Smrg if (y1 < extents.y1) 413d514b0f3Smrg extents.y1 = y1; 414d514b0f3Smrg if (y2 > extents.y2) 415d514b0f3Smrg extents.y2 = y2; 416d514b0f3Smrg } 417d514b0f3Smrg x += glyph->info.xOff; 418d514b0f3Smrg y += glyph->info.yOff; 419d514b0f3Smrg } 420d514b0f3Smrg } 421d514b0f3Smrg 422d514b0f3Smrg return FALSE; 423d514b0f3Smrg} 424d514b0f3Smrg 425d514b0f3Smrgstatic void 426d514b0f3Smrguxa_check_glyphs(CARD8 op, 427d514b0f3Smrg PicturePtr src, 428d514b0f3Smrg PicturePtr dst, 429d514b0f3Smrg PictFormatPtr maskFormat, 430d514b0f3Smrg INT16 xSrc, 431d514b0f3Smrg INT16 ySrc, int nlist, GlyphListPtr list, GlyphPtr * glyphs) 432d514b0f3Smrg{ 433d514b0f3Smrg ScreenPtr pScreen = dst->pDrawable->pScreen; 434d514b0f3Smrg pixman_image_t *image; 435d514b0f3Smrg PixmapPtr scratch; 436d514b0f3Smrg PicturePtr mask; 437d514b0f3Smrg int width = 0, height = 0; 438d514b0f3Smrg int x, y, n; 439d514b0f3Smrg int xDst = list->xOff, yDst = list->yOff; 440d514b0f3Smrg BoxRec extents = { 0, 0, 0, 0 }; 441d514b0f3Smrg 442d514b0f3Smrg if (maskFormat) { 443d514b0f3Smrg pixman_format_code_t format; 444d514b0f3Smrg CARD32 component_alpha; 445d514b0f3Smrg int error; 446d514b0f3Smrg 447d514b0f3Smrg uxa_glyph_extents(nlist, list, glyphs, &extents); 448d514b0f3Smrg if (extents.x2 <= extents.x1 || extents.y2 <= extents.y1) 449d514b0f3Smrg return; 450d514b0f3Smrg 451d514b0f3Smrg width = extents.x2 - extents.x1; 452d514b0f3Smrg height = extents.y2 - extents.y1; 453d514b0f3Smrg 454d514b0f3Smrg format = maskFormat->format | 455d514b0f3Smrg (BitsPerPixel(maskFormat->depth) << 24); 456d514b0f3Smrg image = 457d514b0f3Smrg pixman_image_create_bits(format, width, height, NULL, 0); 458d514b0f3Smrg if (!image) 459d514b0f3Smrg return; 460d514b0f3Smrg 461d514b0f3Smrg scratch = GetScratchPixmapHeader(dst->pDrawable->pScreen, width, height, 462d514b0f3Smrg PIXMAN_FORMAT_DEPTH(format), 463d514b0f3Smrg PIXMAN_FORMAT_BPP(format), 464d514b0f3Smrg pixman_image_get_stride(image), 465d514b0f3Smrg pixman_image_get_data(image)); 466d514b0f3Smrg 467d514b0f3Smrg if (!scratch) { 468d514b0f3Smrg pixman_image_unref(image); 469d514b0f3Smrg return; 470d514b0f3Smrg } 471d514b0f3Smrg 472d514b0f3Smrg component_alpha = NeedsComponent(maskFormat->format); 473d514b0f3Smrg mask = CreatePicture(0, &scratch->drawable, 474d514b0f3Smrg maskFormat, CPComponentAlpha, 475d514b0f3Smrg &component_alpha, serverClient, &error); 476d514b0f3Smrg if (!mask) { 477d514b0f3Smrg FreeScratchPixmapHeader(scratch); 478d514b0f3Smrg pixman_image_unref(image); 479d514b0f3Smrg return; 480d514b0f3Smrg } 481d514b0f3Smrg ValidatePicture(mask); 482d514b0f3Smrg 483d514b0f3Smrg x = -extents.x1; 484d514b0f3Smrg y = -extents.y1; 485d514b0f3Smrg } else { 486d514b0f3Smrg mask = dst; 487d514b0f3Smrg x = 0; 488d514b0f3Smrg y = 0; 489d514b0f3Smrg } 490d514b0f3Smrg 491d514b0f3Smrg while (nlist--) { 492d514b0f3Smrg x += list->xOff; 493d514b0f3Smrg y += list->yOff; 494d514b0f3Smrg n = list->len; 495d514b0f3Smrg while (n--) { 496d514b0f3Smrg GlyphPtr glyph = *glyphs++; 497d514b0f3Smrg PicturePtr g = GetGlyphPicture(glyph, pScreen); 498d514b0f3Smrg if (g) { 499d514b0f3Smrg if (maskFormat) { 500d514b0f3Smrg CompositePicture(PictOpAdd, g, NULL, mask, 501d514b0f3Smrg 0, 0, 502d514b0f3Smrg 0, 0, 503d514b0f3Smrg x - glyph->info.x, 504d514b0f3Smrg y - glyph->info.y, 505d514b0f3Smrg glyph->info.width, 506d514b0f3Smrg glyph->info.height); 507d514b0f3Smrg } else { 508d514b0f3Smrg CompositePicture(op, src, g, dst, 509d514b0f3Smrg xSrc + (x - glyph->info.x) - xDst, 510d514b0f3Smrg ySrc + (y - glyph->info.y) - yDst, 511d514b0f3Smrg 0, 0, 512d514b0f3Smrg x - glyph->info.x, 513d514b0f3Smrg y - glyph->info.y, 514d514b0f3Smrg glyph->info.width, 515d514b0f3Smrg glyph->info.height); 516d514b0f3Smrg } 517d514b0f3Smrg } 518d514b0f3Smrg 519d514b0f3Smrg x += glyph->info.xOff; 520d514b0f3Smrg y += glyph->info.yOff; 521d514b0f3Smrg } 522d514b0f3Smrg list++; 523d514b0f3Smrg } 524d514b0f3Smrg 525d514b0f3Smrg if (maskFormat) { 526d514b0f3Smrg x = extents.x1; 527d514b0f3Smrg y = extents.y1; 528d514b0f3Smrg CompositePicture(op, src, mask, dst, 529d514b0f3Smrg xSrc + x - xDst, 530d514b0f3Smrg ySrc + y - yDst, 531d514b0f3Smrg 0, 0, 532d514b0f3Smrg x, y, 533d514b0f3Smrg width, height); 534d514b0f3Smrg FreePicture(mask, 0); 535d514b0f3Smrg FreeScratchPixmapHeader(scratch); 536d514b0f3Smrg pixman_image_unref(image); 537d514b0f3Smrg } 538d514b0f3Smrg} 539d514b0f3Smrg 540d514b0f3Smrgstatic inline unsigned int 541d514b0f3Smrguxa_glyph_size_to_count(int size) 542d514b0f3Smrg{ 543d514b0f3Smrg size /= GLYPH_MIN_SIZE; 544d514b0f3Smrg return size * size; 545d514b0f3Smrg} 546d514b0f3Smrg 547d514b0f3Smrgstatic inline unsigned int 548d514b0f3Smrguxa_glyph_count_to_mask(int count) 549d514b0f3Smrg{ 550d514b0f3Smrg return ~(count - 1); 551d514b0f3Smrg} 552d514b0f3Smrg 553d514b0f3Smrgstatic inline unsigned int 554d514b0f3Smrguxa_glyph_size_to_mask(int size) 555d514b0f3Smrg{ 556d514b0f3Smrg return uxa_glyph_count_to_mask(uxa_glyph_size_to_count(size)); 557d514b0f3Smrg} 558d514b0f3Smrg 559d514b0f3Smrgstatic PicturePtr 560d514b0f3Smrguxa_glyph_cache(ScreenPtr screen, GlyphPtr glyph, int *out_x, int *out_y) 561d514b0f3Smrg{ 562d514b0f3Smrg uxa_screen_t *uxa_screen = uxa_get_screen(screen); 563d514b0f3Smrg PicturePtr glyph_picture = GetGlyphPicture(glyph, screen); 564d514b0f3Smrg uxa_glyph_cache_t *cache = &uxa_screen->glyphCaches[PICT_FORMAT_RGB(glyph_picture->format) != 0]; 565d514b0f3Smrg struct uxa_glyph *priv = NULL; 566d514b0f3Smrg int size, mask, pos, s; 567d514b0f3Smrg 568d514b0f3Smrg if (glyph->info.width > GLYPH_MAX_SIZE || glyph->info.height > GLYPH_MAX_SIZE) 569d514b0f3Smrg return NULL; 570d514b0f3Smrg 571d514b0f3Smrg for (size = GLYPH_MIN_SIZE; size <= GLYPH_MAX_SIZE; size *= 2) 572d514b0f3Smrg if (glyph->info.width <= size && glyph->info.height <= size) 573d514b0f3Smrg break; 574d514b0f3Smrg 575d514b0f3Smrg s = uxa_glyph_size_to_count(size); 576d514b0f3Smrg mask = uxa_glyph_count_to_mask(s); 577d514b0f3Smrg pos = (cache->count + s - 1) & mask; 578d514b0f3Smrg if (pos < GLYPH_CACHE_SIZE) { 579d514b0f3Smrg cache->count = pos + s; 580d514b0f3Smrg } else { 581d514b0f3Smrg for (s = size; s <= GLYPH_MAX_SIZE; s *= 2) { 582d514b0f3Smrg int i = cache->evict & uxa_glyph_size_to_mask(s); 583d514b0f3Smrg GlyphPtr evicted = cache->glyphs[i]; 584d514b0f3Smrg if (evicted == NULL) 585d514b0f3Smrg continue; 586d514b0f3Smrg 587d514b0f3Smrg priv = uxa_glyph_get_private(evicted); 588d514b0f3Smrg if (priv->size >= s) { 589d514b0f3Smrg cache->glyphs[i] = NULL; 590d514b0f3Smrg uxa_glyph_set_private(evicted, NULL); 591d514b0f3Smrg pos = cache->evict & uxa_glyph_size_to_mask(size); 592d514b0f3Smrg } else 593d514b0f3Smrg priv = NULL; 594d514b0f3Smrg break; 595d514b0f3Smrg } 596d514b0f3Smrg if (priv == NULL) { 597d514b0f3Smrg int count = uxa_glyph_size_to_count(size); 598d514b0f3Smrg mask = uxa_glyph_count_to_mask(count); 599d514b0f3Smrg pos = cache->evict & mask; 600d514b0f3Smrg for (s = 0; s < count; s++) { 601d514b0f3Smrg GlyphPtr evicted = cache->glyphs[pos + s]; 602d514b0f3Smrg if (evicted != NULL) { 603d514b0f3Smrg if (priv != NULL) 604d514b0f3Smrg free(priv); 605d514b0f3Smrg 606d514b0f3Smrg priv = uxa_glyph_get_private(evicted); 607d514b0f3Smrg uxa_glyph_set_private(evicted, NULL); 608d514b0f3Smrg cache->glyphs[pos + s] = NULL; 609d514b0f3Smrg } 610d514b0f3Smrg } 611d514b0f3Smrg } 612d514b0f3Smrg 613d514b0f3Smrg /* And pick a new eviction position */ 614d514b0f3Smrg cache->evict = rand() % GLYPH_CACHE_SIZE; 615d514b0f3Smrg } 616d514b0f3Smrg 617d514b0f3Smrg if (priv == NULL) { 618d514b0f3Smrg priv = malloc(sizeof(struct uxa_glyph)); 619d514b0f3Smrg if (priv == NULL) 620d514b0f3Smrg return NULL; 621d514b0f3Smrg } 622d514b0f3Smrg 623d514b0f3Smrg uxa_glyph_set_private(glyph, priv); 624d514b0f3Smrg cache->glyphs[pos] = glyph; 625d514b0f3Smrg 626d514b0f3Smrg priv->cache = cache; 627d514b0f3Smrg priv->size = size; 628d514b0f3Smrg priv->pos = pos; 629d514b0f3Smrg s = pos / ((GLYPH_MAX_SIZE / GLYPH_MIN_SIZE) * (GLYPH_MAX_SIZE / GLYPH_MIN_SIZE)); 630d514b0f3Smrg priv->x = s % (CACHE_PICTURE_SIZE / GLYPH_MAX_SIZE) * GLYPH_MAX_SIZE; 631d514b0f3Smrg priv->y = (s / (CACHE_PICTURE_SIZE / GLYPH_MAX_SIZE)) * GLYPH_MAX_SIZE; 632d514b0f3Smrg for (s = GLYPH_MIN_SIZE; s < GLYPH_MAX_SIZE; s *= 2) { 633d514b0f3Smrg if (pos & 1) 634d514b0f3Smrg priv->x += s; 635d514b0f3Smrg if (pos & 2) 636d514b0f3Smrg priv->y += s; 637d514b0f3Smrg pos >>= 2; 638d514b0f3Smrg } 639d514b0f3Smrg 640d514b0f3Smrg uxa_glyph_cache_upload_glyph(screen, cache, glyph, priv->x, priv->y); 641d514b0f3Smrg 642d514b0f3Smrg *out_x = priv->x; 643d514b0f3Smrg *out_y = priv->y; 644d514b0f3Smrg return cache->picture; 645d514b0f3Smrg} 646d514b0f3Smrg 647d514b0f3Smrgstatic int 648d514b0f3Smrguxa_glyphs_to_dst(CARD8 op, 649d514b0f3Smrg PicturePtr pSrc, 650d514b0f3Smrg PicturePtr pDst, 651d514b0f3Smrg INT16 src_x, INT16 src_y, 652d514b0f3Smrg INT16 xDst, INT16 yDst, 653d514b0f3Smrg int nlist, GlyphListPtr list, GlyphPtr * glyphs, 654d514b0f3Smrg BoxPtr extents) 655d514b0f3Smrg{ 656d514b0f3Smrg ScreenPtr screen = pDst->pDrawable->pScreen; 657d514b0f3Smrg uxa_screen_t *uxa_screen = uxa_get_screen(screen); 658d514b0f3Smrg PixmapPtr src_pixmap, dst_pixmap; 659d514b0f3Smrg PicturePtr localSrc, glyph_atlas; 660d514b0f3Smrg int x, y, n, nrect; 661d514b0f3Smrg BoxRec box; 662d514b0f3Smrg 663d514b0f3Smrg if (uxa_screen->info->check_composite_texture && 664d514b0f3Smrg uxa_screen->info->check_composite_texture(screen, pSrc)) { 665d514b0f3Smrg if (pSrc->pDrawable) { 666d514b0f3Smrg int src_off_x, src_off_y; 667d514b0f3Smrg 668d514b0f3Smrg src_pixmap = uxa_get_offscreen_pixmap(pSrc->pDrawable, &src_off_x, &src_off_y); 669d514b0f3Smrg if (src_pixmap == NULL) 670d514b0f3Smrg return -1; 671d514b0f3Smrg 672d514b0f3Smrg src_x += pSrc->pDrawable->x + src_off_x; 673d514b0f3Smrg src_y += pSrc->pDrawable->y + src_off_y; 674d514b0f3Smrg } else { 675d514b0f3Smrg src_pixmap = NULL; 676d514b0f3Smrg } 677d514b0f3Smrg localSrc = pSrc; 678d514b0f3Smrg } else { 679d514b0f3Smrg int width, height; 680d514b0f3Smrg 681d514b0f3Smrg if (extents == NULL) { 682d514b0f3Smrg uxa_glyph_extents(nlist, list, glyphs, &box); 683d514b0f3Smrg extents = &box; 684d514b0f3Smrg } 685d514b0f3Smrg 686d514b0f3Smrg width = extents->x2 - extents->x1; 687d514b0f3Smrg height = extents->y2 - extents->y1; 688d514b0f3Smrg if (width == 0 || height == 0) 689d514b0f3Smrg return 0; 690d514b0f3Smrg 691d514b0f3Smrg if (pSrc->pDrawable) { 692d514b0f3Smrg int src_off_x, src_off_y; 693d514b0f3Smrg 694d514b0f3Smrg src_off_x = extents->x1 - xDst; 695d514b0f3Smrg src_off_y = extents->y1 - yDst; 696d514b0f3Smrg localSrc = uxa_acquire_drawable(screen, pSrc, 697d514b0f3Smrg src_x + src_off_x, src_y + src_off_y, 698d514b0f3Smrg width, height, 699d514b0f3Smrg &src_x, &src_y); 700d514b0f3Smrg if (uxa_screen->info->check_composite_texture && 701d514b0f3Smrg !uxa_screen->info->check_composite_texture(screen, localSrc)) { 702d514b0f3Smrg if (localSrc != pSrc) 703d514b0f3Smrg FreePicture(localSrc, 0); 704d514b0f3Smrg return -1; 705d514b0f3Smrg } 706d514b0f3Smrg 707d514b0f3Smrg src_pixmap = uxa_get_offscreen_pixmap(localSrc->pDrawable, &src_off_x, &src_off_y); 708d514b0f3Smrg if (src_pixmap == NULL) { 709d514b0f3Smrg if (localSrc != pSrc) 710d514b0f3Smrg FreePicture(localSrc, 0); 711d514b0f3Smrg return -1; 712d514b0f3Smrg } 713d514b0f3Smrg 714d514b0f3Smrg src_x += localSrc->pDrawable->x + src_off_x; 715d514b0f3Smrg src_y += localSrc->pDrawable->y + src_off_y; 716d514b0f3Smrg } else { 717d514b0f3Smrg localSrc = uxa_acquire_pattern(screen, pSrc, 718d514b0f3Smrg PIXMAN_a8r8g8b8, 0, 0, width, height); 719d514b0f3Smrg if (!localSrc) 720d514b0f3Smrg return 1; 721d514b0f3Smrg 722d514b0f3Smrg src_pixmap = uxa_get_drawable_pixmap(localSrc->pDrawable); 723d514b0f3Smrg if (src_pixmap == NULL) { 724d514b0f3Smrg FreePicture(localSrc, 0); 725d514b0f3Smrg return -1; 726d514b0f3Smrg } 727d514b0f3Smrg 728d514b0f3Smrg src_x = src_y = 0; 729d514b0f3Smrg } 730d514b0f3Smrg } 731d514b0f3Smrg 732d514b0f3Smrg dst_pixmap = uxa_get_offscreen_pixmap(pDst->pDrawable, &x, &y); 733d514b0f3Smrg x += xDst + pDst->pDrawable->x - list->xOff; 734d514b0f3Smrg y += yDst + pDst->pDrawable->y - list->yOff; 735d514b0f3Smrg 736d514b0f3Smrg glyph_atlas = NULL; 737d514b0f3Smrg while (nlist--) { 738d514b0f3Smrg x += list->xOff; 739d514b0f3Smrg y += list->yOff; 740d514b0f3Smrg n = list->len; 741d514b0f3Smrg while (n--) { 742d514b0f3Smrg GlyphPtr glyph = *glyphs++; 743d514b0f3Smrg PicturePtr this_atlas; 744d514b0f3Smrg int mask_x, mask_y; 745d514b0f3Smrg struct uxa_glyph *priv; 746d514b0f3Smrg 747d514b0f3Smrg if (glyph->info.width == 0 || glyph->info.height == 0) 748d514b0f3Smrg goto next_glyph; 749d514b0f3Smrg 750d514b0f3Smrg priv = uxa_glyph_get_private(glyph); 751d514b0f3Smrg if (priv != NULL) { 752d514b0f3Smrg mask_x = priv->x; 753d514b0f3Smrg mask_y = priv->y; 754d514b0f3Smrg this_atlas = priv->cache->picture; 755d514b0f3Smrg } else { 756d514b0f3Smrg if (glyph_atlas) { 757d514b0f3Smrg uxa_screen->info->done_composite(dst_pixmap); 758d514b0f3Smrg glyph_atlas = NULL; 759d514b0f3Smrg } 760d514b0f3Smrg this_atlas = uxa_glyph_cache(screen, glyph, &mask_x, &mask_y); 761d514b0f3Smrg if (this_atlas == NULL) { 762d514b0f3Smrg /* no cache for this glyph */ 763d514b0f3Smrg this_atlas = GetGlyphPicture(glyph, screen); 764d514b0f3Smrg mask_x = mask_y = 0; 765d514b0f3Smrg } 766d514b0f3Smrg } 767d514b0f3Smrg 768d514b0f3Smrg if (this_atlas != glyph_atlas) { 769d514b0f3Smrg PixmapPtr mask_pixmap; 770d514b0f3Smrg 771d514b0f3Smrg if (glyph_atlas) 772d514b0f3Smrg uxa_screen->info->done_composite(dst_pixmap); 773d514b0f3Smrg 774d514b0f3Smrg mask_pixmap = 775d514b0f3Smrg uxa_get_drawable_pixmap(this_atlas->pDrawable); 776d514b0f3Smrg assert (uxa_pixmap_is_offscreen(mask_pixmap)); 777d514b0f3Smrg 778d514b0f3Smrg if (!uxa_screen->info->prepare_composite(op, 779d514b0f3Smrg localSrc, this_atlas, pDst, 780d514b0f3Smrg src_pixmap, mask_pixmap, dst_pixmap)) 781d514b0f3Smrg return -1; 782d514b0f3Smrg 783d514b0f3Smrg glyph_atlas = this_atlas; 784d514b0f3Smrg } 785d514b0f3Smrg 786d514b0f3Smrg nrect = REGION_NUM_RECTS(pDst->pCompositeClip); 787d514b0f3Smrg if (nrect == 1) { 788d514b0f3Smrg uxa_screen->info->composite(dst_pixmap, 789d514b0f3Smrg x + src_x, y + src_y, 790d514b0f3Smrg mask_x, mask_y, 791d514b0f3Smrg x - glyph->info.x, 792d514b0f3Smrg y - glyph->info.y, 793d514b0f3Smrg glyph->info.width, 794d514b0f3Smrg glyph->info.height); 795d514b0f3Smrg } else { 796d514b0f3Smrg BoxPtr rects = REGION_RECTS(pDst->pCompositeClip); 797d514b0f3Smrg do { 798d514b0f3Smrg int x1 = x - glyph->info.x, dx = 0; 799d514b0f3Smrg int y1 = y - glyph->info.y, dy = 0; 800d514b0f3Smrg int x2 = x1 + glyph->info.width; 801d514b0f3Smrg int y2 = y1 + glyph->info.height; 802d514b0f3Smrg 803d514b0f3Smrg if (x1 < rects->x1) 804d514b0f3Smrg dx = rects->x1 - x1, x1 = rects->x1; 805d514b0f3Smrg if (x2 > rects->x2) 806d514b0f3Smrg x2 = rects->x2; 807d514b0f3Smrg if (y1 < rects->y1) 808d514b0f3Smrg dy = rects->y1 - y1, y1 = rects->y1; 809d514b0f3Smrg if (y2 > rects->y2) 810d514b0f3Smrg y2 = rects->y2; 811d514b0f3Smrg 812d514b0f3Smrg if (x1 < x2 && y1 < y2) { 813d514b0f3Smrg uxa_screen->info->composite(dst_pixmap, 814d514b0f3Smrg x1 + src_x, y1 + src_y, 815d514b0f3Smrg dx + mask_x, dy + mask_y, 816d514b0f3Smrg x1, y1, 817d514b0f3Smrg x2 - x1, y2 - y1); 818d514b0f3Smrg } 819d514b0f3Smrg rects++; 820d514b0f3Smrg } while (--nrect); 821d514b0f3Smrg } 822d514b0f3Smrg 823d514b0f3Smrgnext_glyph: 824d514b0f3Smrg x += glyph->info.xOff; 825d514b0f3Smrg y += glyph->info.yOff; 826d514b0f3Smrg } 827d514b0f3Smrg list++; 828d514b0f3Smrg } 829d514b0f3Smrg if (glyph_atlas) 830d514b0f3Smrg uxa_screen->info->done_composite(dst_pixmap); 831d514b0f3Smrg 832d514b0f3Smrg if (localSrc != pSrc) 833d514b0f3Smrg FreePicture(localSrc, 0); 834d514b0f3Smrg 835d514b0f3Smrg return 0; 836d514b0f3Smrg} 837d514b0f3Smrg 838d514b0f3Smrgstatic void 839d514b0f3Smrguxa_clear_pixmap(ScreenPtr screen, 840d514b0f3Smrg uxa_screen_t *uxa_screen, 841d514b0f3Smrg PixmapPtr pixmap) 842d514b0f3Smrg{ 843d514b0f3Smrg if (uxa_screen->info->check_solid && 844d514b0f3Smrg !uxa_screen->info->check_solid(&pixmap->drawable, GXcopy, FB_ALLONES)) 845d514b0f3Smrg goto fallback; 846d514b0f3Smrg 847d514b0f3Smrg if (!uxa_screen->info->prepare_solid(pixmap, GXcopy, FB_ALLONES, 0)) 848d514b0f3Smrg goto fallback; 849d514b0f3Smrg 850d514b0f3Smrg uxa_screen->info->solid(pixmap, 851d514b0f3Smrg 0, 0, 852d514b0f3Smrg pixmap->drawable.width, 853d514b0f3Smrg pixmap->drawable.height); 854d514b0f3Smrg 855d514b0f3Smrg uxa_screen->info->done_solid(pixmap); 856d514b0f3Smrg return; 857d514b0f3Smrg 858d514b0f3Smrgfallback: 859d514b0f3Smrg { 860d514b0f3Smrg GCPtr gc; 861d514b0f3Smrg 862d514b0f3Smrg gc = GetScratchGC(pixmap->drawable.depth, screen); 863d514b0f3Smrg if (gc) { 864d514b0f3Smrg xRectangle rect; 865d514b0f3Smrg 866d514b0f3Smrg ValidateGC(&pixmap->drawable, gc); 867d514b0f3Smrg 868d514b0f3Smrg rect.x = 0; 869d514b0f3Smrg rect.y = 0; 870d514b0f3Smrg rect.width = pixmap->drawable.width; 871d514b0f3Smrg rect.height = pixmap->drawable.height; 872d514b0f3Smrg gc->ops->PolyFillRect(&pixmap->drawable, gc, 1, &rect); 873d514b0f3Smrg 874d514b0f3Smrg FreeScratchGC(gc); 875d514b0f3Smrg } 876d514b0f3Smrg } 877d514b0f3Smrg} 878d514b0f3Smrg 879d514b0f3Smrgstatic int 880d514b0f3Smrguxa_glyphs_via_mask(CARD8 op, 881d514b0f3Smrg PicturePtr pSrc, 882d514b0f3Smrg PicturePtr pDst, 883d514b0f3Smrg PictFormatPtr maskFormat, 884d514b0f3Smrg INT16 xSrc, INT16 ySrc, 885d514b0f3Smrg INT16 xDst, INT16 yDst, 886d514b0f3Smrg int nlist, GlyphListPtr list, GlyphPtr * glyphs, 887d514b0f3Smrg BoxPtr extents) 888d514b0f3Smrg{ 889d514b0f3Smrg ScreenPtr screen = pDst->pDrawable->pScreen; 890d514b0f3Smrg uxa_screen_t *uxa_screen = uxa_get_screen(screen); 891d514b0f3Smrg CARD32 component_alpha; 892d514b0f3Smrg PixmapPtr pixmap; 893d514b0f3Smrg PicturePtr glyph_atlas, mask; 894d514b0f3Smrg int x, y, width, height; 895d514b0f3Smrg int dst_off_x, dst_off_y; 896d514b0f3Smrg int n, error; 897d514b0f3Smrg BoxRec box; 898d514b0f3Smrg 899d514b0f3Smrg if (!extents) { 900d514b0f3Smrg uxa_glyph_extents(nlist, list, glyphs, &box); 901d514b0f3Smrg 902d514b0f3Smrg if (box.x2 <= box.x1 || box.y2 <= box.y1) 903d514b0f3Smrg return 0; 904d514b0f3Smrg 905d514b0f3Smrg extents = &box; 906d514b0f3Smrg dst_off_x = box.x1; 907d514b0f3Smrg dst_off_y = box.y1; 908d514b0f3Smrg } else { 909d514b0f3Smrg dst_off_x = dst_off_y = 0; 910d514b0f3Smrg } 911d514b0f3Smrg 912d514b0f3Smrg width = extents->x2 - extents->x1; 913d514b0f3Smrg height = extents->y2 - extents->y1; 914d514b0f3Smrg x = -extents->x1; 915d514b0f3Smrg y = -extents->y1; 916d514b0f3Smrg 917d514b0f3Smrg if (maskFormat->depth == 1) { 918d514b0f3Smrg PictFormatPtr a8Format = 919d514b0f3Smrg PictureMatchFormat(screen, 8, PICT_a8); 920d514b0f3Smrg 921d514b0f3Smrg if (!a8Format) 922d514b0f3Smrg return -1; 923d514b0f3Smrg 924d514b0f3Smrg maskFormat = a8Format; 925d514b0f3Smrg } 926d514b0f3Smrg 927d514b0f3Smrg pixmap = screen->CreatePixmap(screen, width, height, 928d514b0f3Smrg maskFormat->depth, 929d514b0f3Smrg CREATE_PIXMAP_USAGE_SCRATCH); 930d514b0f3Smrg if (!pixmap) 931d514b0f3Smrg return 1; 932d514b0f3Smrg 933d514b0f3Smrg uxa_clear_pixmap(screen, uxa_screen, pixmap); 934d514b0f3Smrg 935d514b0f3Smrg if (!uxa_pixmap_is_offscreen(pixmap)) { 936d514b0f3Smrg screen->DestroyPixmap(pixmap); 937d514b0f3Smrg return 1; 938d514b0f3Smrg } 939d514b0f3Smrg 940d514b0f3Smrg component_alpha = NeedsComponent(maskFormat->format); 941d514b0f3Smrg mask = CreatePicture(0, &pixmap->drawable, 942d514b0f3Smrg maskFormat, CPComponentAlpha, 943d514b0f3Smrg &component_alpha, serverClient, &error); 944d514b0f3Smrg screen->DestroyPixmap(pixmap); 945d514b0f3Smrg 946d514b0f3Smrg if (!mask) 947d514b0f3Smrg return 1; 948d514b0f3Smrg 949d514b0f3Smrg ValidatePicture(mask); 950d514b0f3Smrg 951d514b0f3Smrg glyph_atlas = NULL; 952d514b0f3Smrg while (nlist--) { 953d514b0f3Smrg x += list->xOff; 954d514b0f3Smrg y += list->yOff; 955d514b0f3Smrg n = list->len; 956d514b0f3Smrg while (n--) { 957d514b0f3Smrg GlyphPtr glyph = *glyphs++; 958d514b0f3Smrg PicturePtr this_atlas; 959d514b0f3Smrg int src_x, src_y; 960d514b0f3Smrg struct uxa_glyph *priv; 961d514b0f3Smrg 962d514b0f3Smrg if (glyph->info.width == 0 || glyph->info.height == 0) 963d514b0f3Smrg goto next_glyph; 964d514b0f3Smrg 965d514b0f3Smrg priv = uxa_glyph_get_private(glyph); 966d514b0f3Smrg if (priv != NULL) { 967d514b0f3Smrg src_x = priv->x; 968d514b0f3Smrg src_y = priv->y; 969d514b0f3Smrg this_atlas = priv->cache->picture; 970d514b0f3Smrg } else { 971d514b0f3Smrg if (glyph_atlas) { 972d514b0f3Smrg uxa_screen->info->done_composite(pixmap); 973d514b0f3Smrg glyph_atlas = NULL; 974d514b0f3Smrg } 975d514b0f3Smrg this_atlas = uxa_glyph_cache(screen, glyph, &src_x, &src_y); 976d514b0f3Smrg if (this_atlas == NULL) { 977d514b0f3Smrg /* no cache for this glyph */ 978d514b0f3Smrg this_atlas = GetGlyphPicture(glyph, screen); 979d514b0f3Smrg src_x = src_y = 0; 980d514b0f3Smrg } 981d514b0f3Smrg } 982d514b0f3Smrg 983d514b0f3Smrg if (this_atlas != glyph_atlas) { 984d514b0f3Smrg PixmapPtr src_pixmap; 985d514b0f3Smrg 986d514b0f3Smrg if (glyph_atlas) 987d514b0f3Smrg uxa_screen->info->done_composite(pixmap); 988d514b0f3Smrg 989d514b0f3Smrg src_pixmap = 990d514b0f3Smrg uxa_get_drawable_pixmap(this_atlas->pDrawable); 991d514b0f3Smrg assert (uxa_pixmap_is_offscreen(src_pixmap)); 992d514b0f3Smrg 993d514b0f3Smrg if (!uxa_screen->info->prepare_composite(PictOpAdd, 994d514b0f3Smrg this_atlas, NULL, mask, 995d514b0f3Smrg src_pixmap, NULL, pixmap)) { 996d514b0f3Smrg FreePicture(mask, 0); 997d514b0f3Smrg return -1; 998d514b0f3Smrg } 999d514b0f3Smrg 1000d514b0f3Smrg glyph_atlas = this_atlas; 1001d514b0f3Smrg } 1002d514b0f3Smrg 1003d514b0f3Smrg uxa_screen->info->composite(pixmap, 1004d514b0f3Smrg src_x, src_y, 1005d514b0f3Smrg 0, 0, 1006d514b0f3Smrg x - glyph->info.x, 1007d514b0f3Smrg y - glyph->info.y, 1008d514b0f3Smrg glyph->info.width, 1009d514b0f3Smrg glyph->info.height); 1010d514b0f3Smrg 1011d514b0f3Smrgnext_glyph: 1012d514b0f3Smrg x += glyph->info.xOff; 1013d514b0f3Smrg y += glyph->info.yOff; 1014d514b0f3Smrg } 1015d514b0f3Smrg list++; 1016d514b0f3Smrg } 1017d514b0f3Smrg if (glyph_atlas) 1018d514b0f3Smrg uxa_screen->info->done_composite(pixmap); 1019d514b0f3Smrg 1020d514b0f3Smrg uxa_composite(op, 1021d514b0f3Smrg pSrc, mask, pDst, 1022d514b0f3Smrg dst_off_x + xSrc - xDst, 1023d514b0f3Smrg dst_off_y + ySrc - yDst, 1024d514b0f3Smrg 0, 0, 1025d514b0f3Smrg dst_off_x, dst_off_y, 1026d514b0f3Smrg width, height); 1027d514b0f3Smrg 1028d514b0f3Smrg FreePicture(mask, 0); 1029d514b0f3Smrg return 0; 1030d514b0f3Smrg} 1031d514b0f3Smrg 1032d514b0f3Smrgvoid 1033d514b0f3Smrguxa_glyphs(CARD8 op, 1034d514b0f3Smrg PicturePtr pSrc, 1035d514b0f3Smrg PicturePtr pDst, 1036d514b0f3Smrg PictFormatPtr maskFormat, 1037d514b0f3Smrg INT16 xSrc, INT16 ySrc, 1038d514b0f3Smrg int nlist, GlyphListPtr list, GlyphPtr * glyphs) 1039d514b0f3Smrg{ 1040d514b0f3Smrg ScreenPtr screen = pDst->pDrawable->pScreen; 1041d514b0f3Smrg uxa_screen_t *uxa_screen = uxa_get_screen(screen); 1042d514b0f3Smrg int xDst = list->xOff, yDst = list->yOff; 1043d514b0f3Smrg BoxRec extents = { 0, 0, 0, 0 }; 1044d514b0f3Smrg Bool have_extents = FALSE; 1045d514b0f3Smrg int width = 0, height = 0, ret; 1046d514b0f3Smrg PicturePtr localDst = pDst; 1047d514b0f3Smrg 1048d514b0f3Smrg if (!uxa_screen->info->prepare_composite || 1049d514b0f3Smrg uxa_screen->swappedOut || 1050d514b0f3Smrg uxa_screen->force_fallback || 1051d514b0f3Smrg !uxa_drawable_is_offscreen(pDst->pDrawable) || 1052d514b0f3Smrg pDst->alphaMap || pSrc->alphaMap) { 1053d514b0f3Smrgfallback: 1054d514b0f3Smrg uxa_check_glyphs(op, pSrc, pDst, maskFormat, xSrc, ySrc, nlist, list, glyphs); 1055d514b0f3Smrg return; 1056d514b0f3Smrg } 1057d514b0f3Smrg 1058d514b0f3Smrg /* basic sanity check */ 1059d514b0f3Smrg if (uxa_screen->info->check_composite && 1060d514b0f3Smrg !uxa_screen->info->check_composite(op, pSrc, NULL, pDst, 0, 0)) { 1061d514b0f3Smrg goto fallback; 1062d514b0f3Smrg } 1063d514b0f3Smrg 1064d514b0f3Smrg ValidatePicture(pSrc); 1065d514b0f3Smrg ValidatePicture(pDst); 1066d514b0f3Smrg 1067d514b0f3Smrg if (!maskFormat) { 1068d514b0f3Smrg /* If we don't have a mask format but all the glyphs have the same format, 1069d514b0f3Smrg * require ComponentAlpha and don't intersect, use the glyph format as mask 1070d514b0f3Smrg * format for the full benefits of the glyph cache. 1071d514b0f3Smrg */ 1072d514b0f3Smrg if (NeedsComponent(list[0].format->format)) { 1073d514b0f3Smrg Bool sameFormat = TRUE; 1074d514b0f3Smrg int i; 1075d514b0f3Smrg 1076d514b0f3Smrg maskFormat = list[0].format; 1077d514b0f3Smrg 1078d514b0f3Smrg for (i = 0; i < nlist; i++) { 1079d514b0f3Smrg if (maskFormat->format != list[i].format->format) { 1080d514b0f3Smrg sameFormat = FALSE; 1081d514b0f3Smrg break; 1082d514b0f3Smrg } 1083d514b0f3Smrg } 1084d514b0f3Smrg 1085d514b0f3Smrg if (!sameFormat || 1086d514b0f3Smrg uxa_glyphs_intersect(nlist, list, glyphs)) 1087d514b0f3Smrg maskFormat = NULL; 1088d514b0f3Smrg } 1089d514b0f3Smrg } 1090d514b0f3Smrg 1091d514b0f3Smrg if (!maskFormat && 1092d514b0f3Smrg uxa_screen->info->check_composite_target && 1093d514b0f3Smrg !uxa_screen->info->check_composite_target(uxa_get_drawable_pixmap(pDst->pDrawable))) { 1094d514b0f3Smrg int depth = pDst->pDrawable->depth; 1095d514b0f3Smrg PixmapPtr pixmap; 1096d514b0f3Smrg int x, y, error; 1097d514b0f3Smrg GCPtr gc; 1098d514b0f3Smrg 1099d514b0f3Smrg pixmap = uxa_get_drawable_pixmap(pDst->pDrawable); 1100d514b0f3Smrg if (uxa_screen->info->check_copy && 1101d514b0f3Smrg !uxa_screen->info->check_copy(pixmap, pixmap, GXcopy, FB_ALLONES)) 1102d514b0f3Smrg goto fallback; 1103d514b0f3Smrg 1104d514b0f3Smrg uxa_glyph_extents(nlist, list, glyphs, &extents); 1105d514b0f3Smrg 1106d514b0f3Smrg /* clip against dst bounds */ 1107d514b0f3Smrg if (extents.x1 < 0) 1108d514b0f3Smrg extents.x1 = 0; 1109d514b0f3Smrg if (extents.y1 < 0) 1110d514b0f3Smrg extents.y1 = 0; 1111d514b0f3Smrg if (extents.x2 > pDst->pDrawable->width) 1112d514b0f3Smrg extents.x2 = pDst->pDrawable->width; 1113d514b0f3Smrg if (extents.y2 > pDst->pDrawable->height) 1114d514b0f3Smrg extents.y2 = pDst->pDrawable->height; 1115d514b0f3Smrg 1116d514b0f3Smrg if (extents.x2 <= extents.x1 || extents.y2 <= extents.y1) 1117d514b0f3Smrg return; 1118d514b0f3Smrg width = extents.x2 - extents.x1; 1119d514b0f3Smrg height = extents.y2 - extents.y1; 1120d514b0f3Smrg x = -extents.x1; 1121d514b0f3Smrg y = -extents.y1; 1122d514b0f3Smrg have_extents = TRUE; 1123d514b0f3Smrg 1124d514b0f3Smrg xDst += x; 1125d514b0f3Smrg yDst += y; 1126d514b0f3Smrg 1127d514b0f3Smrg pixmap = screen->CreatePixmap(screen, 1128d514b0f3Smrg width, height, depth, 1129d514b0f3Smrg CREATE_PIXMAP_USAGE_SCRATCH); 1130d514b0f3Smrg if (!pixmap) 1131d514b0f3Smrg return; 1132d514b0f3Smrg 1133d514b0f3Smrg gc = GetScratchGC(depth, screen); 1134d514b0f3Smrg if (!gc) { 1135d514b0f3Smrg screen->DestroyPixmap(pixmap); 1136d514b0f3Smrg return; 1137d514b0f3Smrg } 1138d514b0f3Smrg 1139d514b0f3Smrg ValidateGC(&pixmap->drawable, gc); 1140d514b0f3Smrg gc->ops->CopyArea(pDst->pDrawable, &pixmap->drawable, gc, 1141d514b0f3Smrg extents.x1, extents.y1, 1142d514b0f3Smrg width, height, 1143d514b0f3Smrg 0, 0); 1144d514b0f3Smrg FreeScratchGC(gc); 1145d514b0f3Smrg 1146d514b0f3Smrg localDst = CreatePicture(0, &pixmap->drawable, 1147d514b0f3Smrg PictureMatchFormat(screen, depth, pDst->format), 1148d514b0f3Smrg 0, 0, serverClient, &error); 1149d514b0f3Smrg screen->DestroyPixmap(pixmap); 1150d514b0f3Smrg 1151d514b0f3Smrg if (!localDst) 1152d514b0f3Smrg return; 1153d514b0f3Smrg 1154d514b0f3Smrg ValidatePicture(localDst); 1155d514b0f3Smrg } 1156d514b0f3Smrg 1157d514b0f3Smrg if (maskFormat) { 1158d514b0f3Smrg ret = uxa_glyphs_via_mask(op, 1159d514b0f3Smrg pSrc, localDst, maskFormat, 1160d514b0f3Smrg xSrc, ySrc, 1161d514b0f3Smrg xDst, yDst, 1162d514b0f3Smrg nlist, list, glyphs, 1163d514b0f3Smrg have_extents ? &extents : NULL); 1164d514b0f3Smrg } else { 1165d514b0f3Smrg ret = uxa_glyphs_to_dst(op, 1166d514b0f3Smrg pSrc, localDst, 1167d514b0f3Smrg xSrc, ySrc, 1168d514b0f3Smrg xDst, yDst, 1169d514b0f3Smrg nlist, list, glyphs, 1170d514b0f3Smrg have_extents ? &extents : NULL); 1171d514b0f3Smrg } 1172d514b0f3Smrg if (ret) { 1173d514b0f3Smrg if (localDst != pDst) 1174d514b0f3Smrg FreePicture(localDst, 0); 1175d514b0f3Smrg 1176d514b0f3Smrg goto fallback; 1177d514b0f3Smrg } 1178d514b0f3Smrg 1179d514b0f3Smrg if (localDst != pDst) { 1180d514b0f3Smrg GCPtr gc; 1181d514b0f3Smrg 1182d514b0f3Smrg gc = GetScratchGC(pDst->pDrawable->depth, screen); 1183d514b0f3Smrg if (gc) { 1184d514b0f3Smrg ValidateGC(pDst->pDrawable, gc); 1185d514b0f3Smrg gc->ops->CopyArea(localDst->pDrawable, pDst->pDrawable, gc, 1186d514b0f3Smrg 0, 0, 1187d514b0f3Smrg width, height, 1188d514b0f3Smrg extents.x1, extents.y1); 1189d514b0f3Smrg FreeScratchGC(gc); 1190d514b0f3Smrg } 1191d514b0f3Smrg 1192d514b0f3Smrg FreePicture(localDst, 0); 1193d514b0f3Smrg } 1194d514b0f3Smrg} 1195