1428d7b3dSmrg/* 2428d7b3dSmrg * Copyright © 2010 Intel Corporation 3428d7b3dSmrg * Partly based on code Copyright © 2008 Red Hat, Inc. 4428d7b3dSmrg * Partly based on code Copyright © 2000 SuSE, Inc. 5428d7b3dSmrg * 6428d7b3dSmrg * Permission to use, copy, modify, distribute, and sell this software and its 7428d7b3dSmrg * documentation for any purpose is hereby granted without fee, provided that 8428d7b3dSmrg * the above copyright notice appear in all copies and that both that 9428d7b3dSmrg * copyright notice and this permission notice appear in supporting 10428d7b3dSmrg * documentation, and that the name of Intel not be used in advertising or 11428d7b3dSmrg * publicity pertaining to distribution of the software without specific, 12428d7b3dSmrg * written prior permission. Intel makes no representations about the 13428d7b3dSmrg * suitability of this software for any purpose. It is provided "as is" 14428d7b3dSmrg * without express or implied warranty. 15428d7b3dSmrg * 16428d7b3dSmrg * INTEL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL 17428d7b3dSmrg * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL INTEL 18428d7b3dSmrg * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 19428d7b3dSmrg * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 20428d7b3dSmrg * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 21428d7b3dSmrg * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 22428d7b3dSmrg * 23428d7b3dSmrg * Permission to use, copy, modify, distribute, and sell this software and its 24428d7b3dSmrg * documentation for any purpose is hereby granted without fee, provided that 25428d7b3dSmrg * the above copyright notice appear in all copies and that both that 26428d7b3dSmrg * copyright notice and this permission notice appear in supporting 27428d7b3dSmrg * documentation, and that the name of Red Hat not be used in advertising or 28428d7b3dSmrg * publicity pertaining to distribution of the software without specific, 29428d7b3dSmrg * written prior permission. Red Hat makes no representations about the 30428d7b3dSmrg * suitability of this software for any purpose. It is provided "as is" 31428d7b3dSmrg * without express or implied warranty. 32428d7b3dSmrg * 33428d7b3dSmrg * Red Hat DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL 34428d7b3dSmrg * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL Red Hat 35428d7b3dSmrg * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 36428d7b3dSmrg * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 37428d7b3dSmrg * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 38428d7b3dSmrg * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 39428d7b3dSmrg * 40428d7b3dSmrg * Permission to use, copy, modify, distribute, and sell this software and its 41428d7b3dSmrg * documentation for any purpose is hereby granted without fee, provided that 42428d7b3dSmrg * the above copyright notice appear in all copies and that both that 43428d7b3dSmrg * copyright notice and this permission notice appear in supporting 44428d7b3dSmrg * documentation, and that the name of SuSE not be used in advertising or 45428d7b3dSmrg * publicity pertaining to distribution of the software without specific, 46428d7b3dSmrg * written prior permission. SuSE makes no representations about the 47428d7b3dSmrg * suitability of this software for any purpose. It is provided "as is" 48428d7b3dSmrg * without express or implied warranty. 49428d7b3dSmrg * 50428d7b3dSmrg * SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL 51428d7b3dSmrg * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE 52428d7b3dSmrg * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 53428d7b3dSmrg * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 54428d7b3dSmrg * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 55428d7b3dSmrg * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 56428d7b3dSmrg * 57428d7b3dSmrg * Author: Chris Wilson <chris@chris-wilson.co.uk> 58428d7b3dSmrg * Based on code by: Keith Packard <keithp@keithp.com> and Owen Taylor <otaylor@fishsoup.net> 59428d7b3dSmrg */ 60428d7b3dSmrg 61428d7b3dSmrg#ifdef HAVE_DIX_CONFIG_H 62428d7b3dSmrg#include <dix-config.h> 63428d7b3dSmrg#endif 64428d7b3dSmrg 65428d7b3dSmrg#include <stdlib.h> 66428d7b3dSmrg 67428d7b3dSmrg#include "uxa-priv.h" 68428d7b3dSmrg#include "common.h" 69428d7b3dSmrg 70428d7b3dSmrg/* Width of the pixmaps we use for the caches; this should be less than 71428d7b3dSmrg * max texture size of the driver; this may need to actually come from 72428d7b3dSmrg * the driver. 73428d7b3dSmrg */ 74428d7b3dSmrg#define CACHE_PICTURE_SIZE 1024 75428d7b3dSmrg#define GLYPH_MIN_SIZE 8 76428d7b3dSmrg#define GLYPH_MAX_SIZE 64 77428d7b3dSmrg#define GLYPH_CACHE_SIZE (CACHE_PICTURE_SIZE * CACHE_PICTURE_SIZE / (GLYPH_MIN_SIZE * GLYPH_MIN_SIZE)) 78428d7b3dSmrg 79428d7b3dSmrgstruct uxa_glyph { 80428d7b3dSmrg uxa_glyph_cache_t *cache; 81428d7b3dSmrg uint16_t x, y; 82428d7b3dSmrg uint16_t size, pos; 83428d7b3dSmrg}; 84428d7b3dSmrg 85428d7b3dSmrg#if HAS_DEVPRIVATEKEYREC 86428d7b3dSmrgstatic DevPrivateKeyRec uxa_glyph_key; 87428d7b3dSmrg#else 88428d7b3dSmrgstatic int uxa_glyph_key; 89428d7b3dSmrg#endif 90428d7b3dSmrg 91428d7b3dSmrgstatic inline struct uxa_glyph *uxa_glyph_get_private(GlyphPtr glyph) 92428d7b3dSmrg{ 93428d7b3dSmrg#if HAS_DEVPRIVATEKEYREC 94428d7b3dSmrg return dixGetPrivate(&glyph->devPrivates, &uxa_glyph_key); 95428d7b3dSmrg#else 96428d7b3dSmrg return dixLookupPrivate(&glyph->devPrivates, &uxa_glyph_key); 97428d7b3dSmrg#endif 98428d7b3dSmrg} 99428d7b3dSmrg 100428d7b3dSmrgstatic inline void uxa_glyph_set_private(GlyphPtr glyph, struct uxa_glyph *priv) 101428d7b3dSmrg{ 102428d7b3dSmrg dixSetPrivate(&glyph->devPrivates, &uxa_glyph_key, priv); 103428d7b3dSmrg} 104428d7b3dSmrg 105428d7b3dSmrg#define NeedsComponent(f) (PICT_FORMAT_A(f) != 0 && PICT_FORMAT_RGB(f) != 0) 106428d7b3dSmrg 107428d7b3dSmrgstatic void uxa_unrealize_glyph_caches(ScreenPtr pScreen) 108428d7b3dSmrg{ 109428d7b3dSmrg uxa_screen_t *uxa_screen = uxa_get_screen(pScreen); 110428d7b3dSmrg int i; 111428d7b3dSmrg 112428d7b3dSmrg if (!uxa_screen->glyph_cache_initialized) 113428d7b3dSmrg return; 114428d7b3dSmrg 115428d7b3dSmrg for (i = 0; i < UXA_NUM_GLYPH_CACHE_FORMATS; i++) { 116428d7b3dSmrg uxa_glyph_cache_t *cache = &uxa_screen->glyphCaches[i]; 117428d7b3dSmrg 118428d7b3dSmrg if (cache->picture) 119428d7b3dSmrg FreePicture(cache->picture, 0); 120428d7b3dSmrg 121428d7b3dSmrg if (cache->glyphs) 122428d7b3dSmrg free(cache->glyphs); 123428d7b3dSmrg } 124428d7b3dSmrg uxa_screen->glyph_cache_initialized = FALSE; 125428d7b3dSmrg} 126428d7b3dSmrg 127428d7b3dSmrgvoid uxa_glyphs_fini(ScreenPtr pScreen) 128428d7b3dSmrg{ 129428d7b3dSmrg uxa_unrealize_glyph_caches(pScreen); 130428d7b3dSmrg} 131428d7b3dSmrg 132428d7b3dSmrg/* All caches for a single format share a single pixmap for glyph storage, 133428d7b3dSmrg * allowing mixing glyphs of different sizes without paying a penalty 134428d7b3dSmrg * for switching between source pixmaps. (Note that for a size of font 135428d7b3dSmrg * right at the border between two sizes, we might be switching for almost 136428d7b3dSmrg * every glyph.) 137428d7b3dSmrg * 138428d7b3dSmrg * This function allocates the storage pixmap, and then fills in the 139428d7b3dSmrg * rest of the allocated structures for all caches with the given format. 140428d7b3dSmrg */ 141428d7b3dSmrgstatic Bool uxa_realize_glyph_caches(ScreenPtr pScreen) 142428d7b3dSmrg{ 143428d7b3dSmrg uxa_screen_t *uxa_screen = uxa_get_screen(pScreen); 144428d7b3dSmrg unsigned int formats[] = { 145428d7b3dSmrg PIXMAN_a8, 146428d7b3dSmrg PIXMAN_a8r8g8b8, 147428d7b3dSmrg }; 148428d7b3dSmrg unsigned i; 149428d7b3dSmrg 150428d7b3dSmrg if (uxa_screen->glyph_cache_initialized) 151428d7b3dSmrg return TRUE; 152428d7b3dSmrg 153428d7b3dSmrg uxa_screen->glyph_cache_initialized = TRUE; 154428d7b3dSmrg memset(uxa_screen->glyphCaches, 0, sizeof(uxa_screen->glyphCaches)); 155428d7b3dSmrg 156428d7b3dSmrg for (i = 0; i < sizeof(formats)/sizeof(formats[0]); i++) { 157428d7b3dSmrg uxa_glyph_cache_t *cache = &uxa_screen->glyphCaches[i]; 158428d7b3dSmrg PixmapPtr pixmap; 159428d7b3dSmrg PicturePtr picture; 160428d7b3dSmrg CARD32 component_alpha; 161428d7b3dSmrg int depth = PIXMAN_FORMAT_DEPTH(formats[i]); 162428d7b3dSmrg int error; 163428d7b3dSmrg PictFormatPtr pPictFormat = PictureMatchFormat(pScreen, depth, formats[i]); 164428d7b3dSmrg if (!pPictFormat) 165428d7b3dSmrg goto bail; 166428d7b3dSmrg 167428d7b3dSmrg /* Now allocate the pixmap and picture */ 168428d7b3dSmrg pixmap = pScreen->CreatePixmap(pScreen, 169428d7b3dSmrg CACHE_PICTURE_SIZE, CACHE_PICTURE_SIZE, depth, 170428d7b3dSmrg INTEL_CREATE_PIXMAP_TILING_X); 171428d7b3dSmrg if (!pixmap) 172428d7b3dSmrg goto bail; 173428d7b3dSmrg if (!uxa_pixmap_is_offscreen(pixmap)) { 174428d7b3dSmrg /* Presume shadow is in-effect */ 175428d7b3dSmrg pScreen->DestroyPixmap(pixmap); 176428d7b3dSmrg uxa_unrealize_glyph_caches(pScreen); 177428d7b3dSmrg return TRUE; 178428d7b3dSmrg } 179428d7b3dSmrg 180428d7b3dSmrg component_alpha = NeedsComponent(pPictFormat->format); 181428d7b3dSmrg picture = CreatePicture(0, &pixmap->drawable, pPictFormat, 182428d7b3dSmrg CPComponentAlpha, &component_alpha, 183428d7b3dSmrg serverClient, &error); 184428d7b3dSmrg 185428d7b3dSmrg pScreen->DestroyPixmap(pixmap); 186428d7b3dSmrg 187428d7b3dSmrg if (!picture) 188428d7b3dSmrg goto bail; 189428d7b3dSmrg 190428d7b3dSmrg ValidatePicture(picture); 191428d7b3dSmrg 192428d7b3dSmrg cache->picture = picture; 193428d7b3dSmrg cache->glyphs = calloc(sizeof(GlyphPtr), GLYPH_CACHE_SIZE); 194428d7b3dSmrg if (!cache->glyphs) 195428d7b3dSmrg goto bail; 196428d7b3dSmrg 197428d7b3dSmrg cache->evict = rand() % GLYPH_CACHE_SIZE; 198428d7b3dSmrg } 199428d7b3dSmrg assert(i == UXA_NUM_GLYPH_CACHE_FORMATS); 200428d7b3dSmrg 201428d7b3dSmrg return TRUE; 202428d7b3dSmrg 203428d7b3dSmrgbail: 204428d7b3dSmrg uxa_unrealize_glyph_caches(pScreen); 205428d7b3dSmrg return FALSE; 206428d7b3dSmrg} 207428d7b3dSmrg 208428d7b3dSmrg 209428d7b3dSmrgBool uxa_glyphs_init(ScreenPtr pScreen) 210428d7b3dSmrg{ 211428d7b3dSmrg 212428d7b3dSmrg#if HAS_DIXREGISTERPRIVATEKEY 213428d7b3dSmrg if (!dixRegisterPrivateKey(&uxa_glyph_key, PRIVATE_GLYPH, 0)) 214428d7b3dSmrg return FALSE; 215428d7b3dSmrg#else 216428d7b3dSmrg if (!dixRequestPrivate(&uxa_glyph_key, 0)) 217428d7b3dSmrg return FALSE; 218428d7b3dSmrg#endif 219428d7b3dSmrg 220428d7b3dSmrg /* Skip pixmap creation if we don't intend to use it. */ 221428d7b3dSmrg if (uxa_get_screen(pScreen)->force_fallback) 222428d7b3dSmrg return TRUE; 223428d7b3dSmrg 224428d7b3dSmrg return uxa_realize_glyph_caches(pScreen); 225428d7b3dSmrg} 226428d7b3dSmrg 227428d7b3dSmrg/* The most efficient thing to way to upload the glyph to the screen 228428d7b3dSmrg * is to use CopyArea; uxa pixmaps are always offscreen. 229428d7b3dSmrg */ 230428d7b3dSmrgstatic void 231428d7b3dSmrguxa_glyph_cache_upload_glyph(ScreenPtr screen, 232428d7b3dSmrg uxa_glyph_cache_t * cache, 233428d7b3dSmrg GlyphPtr glyph, 234428d7b3dSmrg int x, int y) 235428d7b3dSmrg{ 236428d7b3dSmrg PicturePtr pGlyphPicture = GetGlyphPicture(glyph, screen); 237428d7b3dSmrg PixmapPtr pGlyphPixmap = (PixmapPtr) pGlyphPicture->pDrawable; 238428d7b3dSmrg PixmapPtr pCachePixmap = (PixmapPtr) cache->picture->pDrawable; 239428d7b3dSmrg PixmapPtr scratch; 240428d7b3dSmrg GCPtr gc; 241428d7b3dSmrg 242428d7b3dSmrg gc = GetScratchGC(pCachePixmap->drawable.depth, screen); 243428d7b3dSmrg if (!gc) 244428d7b3dSmrg return; 245428d7b3dSmrg 246428d7b3dSmrg ValidateGC(&pCachePixmap->drawable, gc); 247428d7b3dSmrg 248428d7b3dSmrg scratch = pGlyphPixmap; 249428d7b3dSmrg /* Create a temporary bo to stream the updates to the cache */ 250428d7b3dSmrg if (pGlyphPixmap->drawable.depth != pCachePixmap->drawable.depth || 251428d7b3dSmrg !uxa_pixmap_is_offscreen(scratch)) { 252428d7b3dSmrg scratch = screen->CreatePixmap(screen, 253428d7b3dSmrg glyph->info.width, 254428d7b3dSmrg glyph->info.height, 255428d7b3dSmrg pCachePixmap->drawable.depth, 256428d7b3dSmrg UXA_CREATE_PIXMAP_FOR_MAP); 257428d7b3dSmrg if (scratch) { 258428d7b3dSmrg if (pGlyphPixmap->drawable.depth != pCachePixmap->drawable.depth) { 259428d7b3dSmrg PicturePtr picture; 260428d7b3dSmrg int error; 261428d7b3dSmrg 262428d7b3dSmrg picture = CreatePicture(0, &scratch->drawable, 263428d7b3dSmrg PictureMatchFormat(screen, 264428d7b3dSmrg pCachePixmap->drawable.depth, 265428d7b3dSmrg cache->picture->format), 266428d7b3dSmrg 0, NULL, 267428d7b3dSmrg serverClient, &error); 268428d7b3dSmrg if (picture) { 269428d7b3dSmrg ValidatePicture(picture); 270428d7b3dSmrg uxa_composite(PictOpSrc, pGlyphPicture, NULL, picture, 271428d7b3dSmrg 0, 0, 272428d7b3dSmrg 0, 0, 273428d7b3dSmrg 0, 0, 274428d7b3dSmrg glyph->info.width, glyph->info.height); 275428d7b3dSmrg FreePicture(picture, 0); 276428d7b3dSmrg } 277428d7b3dSmrg } else { 278428d7b3dSmrg uxa_copy_area(&pGlyphPixmap->drawable, 279428d7b3dSmrg &scratch->drawable, 280428d7b3dSmrg gc, 281428d7b3dSmrg 0, 0, 282428d7b3dSmrg glyph->info.width, glyph->info.height, 283428d7b3dSmrg 0, 0); 284428d7b3dSmrg } 285428d7b3dSmrg } else { 286428d7b3dSmrg scratch = pGlyphPixmap; 287428d7b3dSmrg } 288428d7b3dSmrg } 289428d7b3dSmrg 290428d7b3dSmrg uxa_copy_area(&scratch->drawable, &pCachePixmap->drawable, gc, 291428d7b3dSmrg 0, 0, 292428d7b3dSmrg glyph->info.width, glyph->info.height, 293428d7b3dSmrg x, y); 294428d7b3dSmrg 295428d7b3dSmrg if (scratch != pGlyphPixmap) 296428d7b3dSmrg screen->DestroyPixmap(scratch); 297428d7b3dSmrg 298428d7b3dSmrg FreeScratchGC(gc); 299428d7b3dSmrg} 300428d7b3dSmrg 301428d7b3dSmrgvoid 302428d7b3dSmrguxa_glyph_unrealize(ScreenPtr screen, 303428d7b3dSmrg GlyphPtr glyph) 304428d7b3dSmrg{ 305428d7b3dSmrg struct uxa_glyph *priv; 306428d7b3dSmrg 307428d7b3dSmrg /* Use Lookup in case we have not attached to this glyph. */ 308428d7b3dSmrg priv = dixLookupPrivate(&glyph->devPrivates, &uxa_glyph_key); 309428d7b3dSmrg if (priv == NULL) 310428d7b3dSmrg return; 311428d7b3dSmrg 312428d7b3dSmrg priv->cache->glyphs[priv->pos] = NULL; 313428d7b3dSmrg 314428d7b3dSmrg uxa_glyph_set_private(glyph, NULL); 315428d7b3dSmrg free(priv); 316428d7b3dSmrg} 317428d7b3dSmrg 318428d7b3dSmrg/* Cut and paste from render/glyph.c - probably should export it instead */ 319428d7b3dSmrgstatic void 320428d7b3dSmrguxa_glyph_extents(int nlist, 321428d7b3dSmrg GlyphListPtr list, GlyphPtr * glyphs, BoxPtr extents) 322428d7b3dSmrg{ 323428d7b3dSmrg int x1, x2, y1, y2; 324428d7b3dSmrg int x, y, n; 325428d7b3dSmrg 326428d7b3dSmrg x1 = y1 = MAXSHORT; 327428d7b3dSmrg x2 = y2 = MINSHORT; 328428d7b3dSmrg x = y = 0; 329428d7b3dSmrg while (nlist--) { 330428d7b3dSmrg x += list->xOff; 331428d7b3dSmrg y += list->yOff; 332428d7b3dSmrg n = list->len; 333428d7b3dSmrg list++; 334428d7b3dSmrg while (n--) { 335428d7b3dSmrg GlyphPtr glyph = *glyphs++; 336428d7b3dSmrg int v; 337428d7b3dSmrg 338428d7b3dSmrg v = x - glyph->info.x; 339428d7b3dSmrg if (v < x1) 340428d7b3dSmrg x1 = v; 341428d7b3dSmrg v += glyph->info.width; 342428d7b3dSmrg if (v > x2) 343428d7b3dSmrg x2 = v; 344428d7b3dSmrg 345428d7b3dSmrg v = y - glyph->info.y; 346428d7b3dSmrg if (v < y1) 347428d7b3dSmrg y1 = v; 348428d7b3dSmrg v += glyph->info.height; 349428d7b3dSmrg if (v > y2) 350428d7b3dSmrg y2 = v; 351428d7b3dSmrg 352428d7b3dSmrg x += glyph->info.xOff; 353428d7b3dSmrg y += glyph->info.yOff; 354428d7b3dSmrg } 355428d7b3dSmrg } 356428d7b3dSmrg 357428d7b3dSmrg extents->x1 = x1 < MINSHORT ? MINSHORT : x1; 358428d7b3dSmrg extents->x2 = x2 > MAXSHORT ? MAXSHORT : x2; 359428d7b3dSmrg extents->y1 = y1 < MINSHORT ? MINSHORT : y1; 360428d7b3dSmrg extents->y2 = y2 > MAXSHORT ? MAXSHORT : y2; 361428d7b3dSmrg} 362428d7b3dSmrg 363428d7b3dSmrg/** 364428d7b3dSmrg * Returns TRUE if the glyphs in the lists intersect. Only checks based on 365428d7b3dSmrg * bounding box, which appears to be good enough to catch most cases at least. 366428d7b3dSmrg */ 367428d7b3dSmrgstatic Bool 368428d7b3dSmrguxa_glyphs_intersect(int nlist, GlyphListPtr list, GlyphPtr * glyphs) 369428d7b3dSmrg{ 370428d7b3dSmrg int x1, x2, y1, y2; 371428d7b3dSmrg int n; 372428d7b3dSmrg int x, y; 373428d7b3dSmrg BoxRec extents; 374428d7b3dSmrg Bool first = TRUE; 375428d7b3dSmrg 376428d7b3dSmrg x = 0; 377428d7b3dSmrg y = 0; 378428d7b3dSmrg extents.x1 = 0; 379428d7b3dSmrg extents.y1 = 0; 380428d7b3dSmrg extents.x2 = 0; 381428d7b3dSmrg extents.y2 = 0; 382428d7b3dSmrg while (nlist--) { 383428d7b3dSmrg x += list->xOff; 384428d7b3dSmrg y += list->yOff; 385428d7b3dSmrg n = list->len; 386428d7b3dSmrg list++; 387428d7b3dSmrg while (n--) { 388428d7b3dSmrg GlyphPtr glyph = *glyphs++; 389428d7b3dSmrg 390428d7b3dSmrg if (glyph->info.width == 0 || glyph->info.height == 0) { 391428d7b3dSmrg x += glyph->info.xOff; 392428d7b3dSmrg y += glyph->info.yOff; 393428d7b3dSmrg continue; 394428d7b3dSmrg } 395428d7b3dSmrg 396428d7b3dSmrg x1 = x - glyph->info.x; 397428d7b3dSmrg if (x1 < MINSHORT) 398428d7b3dSmrg x1 = MINSHORT; 399428d7b3dSmrg y1 = y - glyph->info.y; 400428d7b3dSmrg if (y1 < MINSHORT) 401428d7b3dSmrg y1 = MINSHORT; 402428d7b3dSmrg x2 = x1 + glyph->info.width; 403428d7b3dSmrg if (x2 > MAXSHORT) 404428d7b3dSmrg x2 = MAXSHORT; 405428d7b3dSmrg y2 = y1 + glyph->info.height; 406428d7b3dSmrg if (y2 > MAXSHORT) 407428d7b3dSmrg y2 = MAXSHORT; 408428d7b3dSmrg 409428d7b3dSmrg if (first) { 410428d7b3dSmrg extents.x1 = x1; 411428d7b3dSmrg extents.y1 = y1; 412428d7b3dSmrg extents.x2 = x2; 413428d7b3dSmrg extents.y2 = y2; 414428d7b3dSmrg first = FALSE; 415428d7b3dSmrg } else { 416428d7b3dSmrg if (x1 < extents.x2 && x2 > extents.x1 && 417428d7b3dSmrg y1 < extents.y2 && y2 > extents.y1) { 418428d7b3dSmrg return TRUE; 419428d7b3dSmrg } 420428d7b3dSmrg 421428d7b3dSmrg if (x1 < extents.x1) 422428d7b3dSmrg extents.x1 = x1; 423428d7b3dSmrg if (x2 > extents.x2) 424428d7b3dSmrg extents.x2 = x2; 425428d7b3dSmrg if (y1 < extents.y1) 426428d7b3dSmrg extents.y1 = y1; 427428d7b3dSmrg if (y2 > extents.y2) 428428d7b3dSmrg extents.y2 = y2; 429428d7b3dSmrg } 430428d7b3dSmrg x += glyph->info.xOff; 431428d7b3dSmrg y += glyph->info.yOff; 432428d7b3dSmrg } 433428d7b3dSmrg } 434428d7b3dSmrg 435428d7b3dSmrg return FALSE; 436428d7b3dSmrg} 437428d7b3dSmrg 438428d7b3dSmrgstatic void 439428d7b3dSmrguxa_check_glyphs(CARD8 op, 440428d7b3dSmrg PicturePtr src, 441428d7b3dSmrg PicturePtr dst, 442428d7b3dSmrg PictFormatPtr maskFormat, 443428d7b3dSmrg INT16 xSrc, 444428d7b3dSmrg INT16 ySrc, int nlist, GlyphListPtr list, GlyphPtr * glyphs) 445428d7b3dSmrg{ 446428d7b3dSmrg pixman_image_t *image; 447428d7b3dSmrg PixmapPtr scratch; 448428d7b3dSmrg PicturePtr mask, mask_src = NULL, mask_dst = NULL, white = NULL; 449428d7b3dSmrg int width = 0, height = 0; 450428d7b3dSmrg int x, y, n; 451428d7b3dSmrg int xDst = list->xOff, yDst = list->yOff; 452428d7b3dSmrg BoxRec extents = { 0, 0, 0, 0 }; 453428d7b3dSmrg CARD8 mask_op = 0; 454428d7b3dSmrg 455428d7b3dSmrg if (maskFormat) { 456428d7b3dSmrg pixman_format_code_t format; 457428d7b3dSmrg CARD32 component_alpha; 458428d7b3dSmrg xRenderColor color; 459428d7b3dSmrg int error; 460428d7b3dSmrg 461428d7b3dSmrg uxa_glyph_extents(nlist, list, glyphs, &extents); 462428d7b3dSmrg if (extents.x2 <= extents.x1 || extents.y2 <= extents.y1) 463428d7b3dSmrg return; 464428d7b3dSmrg 465428d7b3dSmrg width = extents.x2 - extents.x1; 466428d7b3dSmrg height = extents.y2 - extents.y1; 467428d7b3dSmrg 468428d7b3dSmrg format = maskFormat->format | 469428d7b3dSmrg (BitsPerPixel(maskFormat->depth) << 24); 470428d7b3dSmrg image = 471428d7b3dSmrg pixman_image_create_bits(format, width, height, NULL, 0); 472428d7b3dSmrg if (!image) 473428d7b3dSmrg return; 474428d7b3dSmrg 475428d7b3dSmrg scratch = GetScratchPixmapHeader(dst->pDrawable->pScreen, width, height, 476428d7b3dSmrg PIXMAN_FORMAT_DEPTH(format), 477428d7b3dSmrg PIXMAN_FORMAT_BPP(format), 478428d7b3dSmrg pixman_image_get_stride(image), 479428d7b3dSmrg pixman_image_get_data(image)); 480428d7b3dSmrg 481428d7b3dSmrg if (!scratch) { 482428d7b3dSmrg pixman_image_unref(image); 483428d7b3dSmrg return; 484428d7b3dSmrg } 485428d7b3dSmrg 486428d7b3dSmrg component_alpha = NeedsComponent(maskFormat->format); 487428d7b3dSmrg mask = CreatePicture(0, &scratch->drawable, 488428d7b3dSmrg maskFormat, CPComponentAlpha, 489428d7b3dSmrg &component_alpha, serverClient, &error); 490428d7b3dSmrg if (!mask) { 491428d7b3dSmrg FreeScratchPixmapHeader(scratch); 492428d7b3dSmrg pixman_image_unref(image); 493428d7b3dSmrg return; 494428d7b3dSmrg } 495428d7b3dSmrg ValidatePicture(mask); 496428d7b3dSmrg 497428d7b3dSmrg x = -extents.x1; 498428d7b3dSmrg y = -extents.y1; 499428d7b3dSmrg 500428d7b3dSmrg color.red = color.green = color.blue = color.alpha = 0xffff; 501428d7b3dSmrg white = CreateSolidPicture(0, &color, &error); 502428d7b3dSmrg 503428d7b3dSmrg mask_op = op; 504428d7b3dSmrg op = PictOpAdd; 505428d7b3dSmrg 506428d7b3dSmrg mask_src = src; 507428d7b3dSmrg src = white; 508428d7b3dSmrg 509428d7b3dSmrg mask_dst = dst; 510428d7b3dSmrg dst = mask; 511428d7b3dSmrg } else { 512428d7b3dSmrg mask = dst; 513428d7b3dSmrg x = 0; 514428d7b3dSmrg y = 0; 515428d7b3dSmrg } 516428d7b3dSmrg 517428d7b3dSmrg while (nlist--) { 518428d7b3dSmrg x += list->xOff; 519428d7b3dSmrg y += list->yOff; 520428d7b3dSmrg n = list->len; 521428d7b3dSmrg while (n--) { 522428d7b3dSmrg GlyphPtr glyph = *glyphs++; 523428d7b3dSmrg PicturePtr g = GetGlyphPicture(glyph, dst->pDrawable->pScreen); 524428d7b3dSmrg if (g) { 525428d7b3dSmrg CompositePicture(op, src, g, dst, 526428d7b3dSmrg xSrc + (x - glyph->info.x) - xDst, 527428d7b3dSmrg ySrc + (y - glyph->info.y) - yDst, 528428d7b3dSmrg 0, 0, 529428d7b3dSmrg x - glyph->info.x, 530428d7b3dSmrg y - glyph->info.y, 531428d7b3dSmrg glyph->info.width, 532428d7b3dSmrg glyph->info.height); 533428d7b3dSmrg } 534428d7b3dSmrg 535428d7b3dSmrg x += glyph->info.xOff; 536428d7b3dSmrg y += glyph->info.yOff; 537428d7b3dSmrg } 538428d7b3dSmrg list++; 539428d7b3dSmrg } 540428d7b3dSmrg 541428d7b3dSmrg if (white) 542428d7b3dSmrg FreePicture(white, 0); 543428d7b3dSmrg 544428d7b3dSmrg if (maskFormat) { 545428d7b3dSmrg x = extents.x1; 546428d7b3dSmrg y = extents.y1; 547428d7b3dSmrg CompositePicture(mask_op, mask_src, mask, mask_dst, 548428d7b3dSmrg xSrc + x - xDst, 549428d7b3dSmrg ySrc + y - yDst, 550428d7b3dSmrg 0, 0, 551428d7b3dSmrg x, y, 552428d7b3dSmrg width, height); 553428d7b3dSmrg FreePicture(mask, 0); 554428d7b3dSmrg FreeScratchPixmapHeader(scratch); 555428d7b3dSmrg pixman_image_unref(image); 556428d7b3dSmrg } 557428d7b3dSmrg} 558428d7b3dSmrg 559428d7b3dSmrgstatic inline unsigned int 560428d7b3dSmrguxa_glyph_size_to_count(int size) 561428d7b3dSmrg{ 562428d7b3dSmrg size /= GLYPH_MIN_SIZE; 563428d7b3dSmrg return size * size; 564428d7b3dSmrg} 565428d7b3dSmrg 566428d7b3dSmrgstatic inline unsigned int 567428d7b3dSmrguxa_glyph_count_to_mask(int count) 568428d7b3dSmrg{ 569428d7b3dSmrg return ~(count - 1); 570428d7b3dSmrg} 571428d7b3dSmrg 572428d7b3dSmrgstatic inline unsigned int 573428d7b3dSmrguxa_glyph_size_to_mask(int size) 574428d7b3dSmrg{ 575428d7b3dSmrg return uxa_glyph_count_to_mask(uxa_glyph_size_to_count(size)); 576428d7b3dSmrg} 577428d7b3dSmrg 578428d7b3dSmrgstatic PicturePtr 579428d7b3dSmrguxa_glyph_cache(ScreenPtr screen, GlyphPtr glyph, int *out_x, int *out_y) 580428d7b3dSmrg{ 581428d7b3dSmrg uxa_screen_t *uxa_screen = uxa_get_screen(screen); 582428d7b3dSmrg PicturePtr glyph_picture = GetGlyphPicture(glyph, screen); 583428d7b3dSmrg uxa_glyph_cache_t *cache = &uxa_screen->glyphCaches[PICT_FORMAT_RGB(glyph_picture->format) != 0]; 584428d7b3dSmrg struct uxa_glyph *priv = NULL; 585428d7b3dSmrg int size, mask, pos, s; 586428d7b3dSmrg 587428d7b3dSmrg if (glyph->info.width > GLYPH_MAX_SIZE || glyph->info.height > GLYPH_MAX_SIZE) 588428d7b3dSmrg return NULL; 589428d7b3dSmrg 590428d7b3dSmrg for (size = GLYPH_MIN_SIZE; size <= GLYPH_MAX_SIZE; size *= 2) 591428d7b3dSmrg if (glyph->info.width <= size && glyph->info.height <= size) 592428d7b3dSmrg break; 593428d7b3dSmrg 594428d7b3dSmrg s = uxa_glyph_size_to_count(size); 595428d7b3dSmrg mask = uxa_glyph_count_to_mask(s); 596428d7b3dSmrg pos = (cache->count + s - 1) & mask; 597428d7b3dSmrg if (pos < GLYPH_CACHE_SIZE) { 598428d7b3dSmrg cache->count = pos + s; 599428d7b3dSmrg } else { 600428d7b3dSmrg for (s = size; s <= GLYPH_MAX_SIZE; s *= 2) { 601428d7b3dSmrg int i = cache->evict & uxa_glyph_size_to_mask(s); 602428d7b3dSmrg GlyphPtr evicted = cache->glyphs[i]; 603428d7b3dSmrg if (evicted == NULL) 604428d7b3dSmrg continue; 605428d7b3dSmrg 606428d7b3dSmrg priv = uxa_glyph_get_private(evicted); 607428d7b3dSmrg if (priv->size >= s) { 608428d7b3dSmrg cache->glyphs[i] = NULL; 609428d7b3dSmrg uxa_glyph_set_private(evicted, NULL); 610428d7b3dSmrg pos = cache->evict & uxa_glyph_size_to_mask(size); 611428d7b3dSmrg } else 612428d7b3dSmrg priv = NULL; 613428d7b3dSmrg break; 614428d7b3dSmrg } 615428d7b3dSmrg if (priv == NULL) { 616428d7b3dSmrg int count = uxa_glyph_size_to_count(size); 617428d7b3dSmrg mask = uxa_glyph_count_to_mask(count); 618428d7b3dSmrg pos = cache->evict & mask; 619428d7b3dSmrg for (s = 0; s < count; s++) { 620428d7b3dSmrg GlyphPtr evicted = cache->glyphs[pos + s]; 621428d7b3dSmrg if (evicted != NULL) { 622428d7b3dSmrg if (priv != NULL) 623428d7b3dSmrg free(priv); 624428d7b3dSmrg 625428d7b3dSmrg priv = uxa_glyph_get_private(evicted); 626428d7b3dSmrg uxa_glyph_set_private(evicted, NULL); 627428d7b3dSmrg cache->glyphs[pos + s] = NULL; 628428d7b3dSmrg } 629428d7b3dSmrg } 630428d7b3dSmrg } 631428d7b3dSmrg 632428d7b3dSmrg /* And pick a new eviction position */ 633428d7b3dSmrg cache->evict = rand() % GLYPH_CACHE_SIZE; 634428d7b3dSmrg } 635428d7b3dSmrg 636428d7b3dSmrg if (priv == NULL) { 637428d7b3dSmrg priv = malloc(sizeof(struct uxa_glyph)); 638428d7b3dSmrg if (priv == NULL) 639428d7b3dSmrg return NULL; 640428d7b3dSmrg } 641428d7b3dSmrg 642428d7b3dSmrg uxa_glyph_set_private(glyph, priv); 643428d7b3dSmrg cache->glyphs[pos] = glyph; 644428d7b3dSmrg 645428d7b3dSmrg priv->cache = cache; 646428d7b3dSmrg priv->size = size; 647428d7b3dSmrg priv->pos = pos; 648428d7b3dSmrg s = pos / ((GLYPH_MAX_SIZE / GLYPH_MIN_SIZE) * (GLYPH_MAX_SIZE / GLYPH_MIN_SIZE)); 649428d7b3dSmrg priv->x = s % (CACHE_PICTURE_SIZE / GLYPH_MAX_SIZE) * GLYPH_MAX_SIZE; 650428d7b3dSmrg priv->y = (s / (CACHE_PICTURE_SIZE / GLYPH_MAX_SIZE)) * GLYPH_MAX_SIZE; 651428d7b3dSmrg for (s = GLYPH_MIN_SIZE; s < GLYPH_MAX_SIZE; s *= 2) { 652428d7b3dSmrg if (pos & 1) 653428d7b3dSmrg priv->x += s; 654428d7b3dSmrg if (pos & 2) 655428d7b3dSmrg priv->y += s; 656428d7b3dSmrg pos >>= 2; 657428d7b3dSmrg } 658428d7b3dSmrg 659428d7b3dSmrg uxa_glyph_cache_upload_glyph(screen, cache, glyph, priv->x, priv->y); 660428d7b3dSmrg 661428d7b3dSmrg *out_x = priv->x; 662428d7b3dSmrg *out_y = priv->y; 663428d7b3dSmrg return cache->picture; 664428d7b3dSmrg} 665428d7b3dSmrg 666428d7b3dSmrgstatic void 667428d7b3dSmrguxa_clear_pixmap(ScreenPtr screen, 668428d7b3dSmrg uxa_screen_t *uxa_screen, 669428d7b3dSmrg PixmapPtr pixmap) 670428d7b3dSmrg{ 671428d7b3dSmrg if (uxa_screen->info->check_solid && 672428d7b3dSmrg !uxa_screen->info->check_solid(&pixmap->drawable, GXcopy, FB_ALLONES)) 673428d7b3dSmrg goto fallback; 674428d7b3dSmrg 675428d7b3dSmrg if (!uxa_screen->info->prepare_solid(pixmap, GXcopy, FB_ALLONES, 0)) 676428d7b3dSmrg goto fallback; 677428d7b3dSmrg 678428d7b3dSmrg uxa_screen->info->solid(pixmap, 679428d7b3dSmrg 0, 0, 680428d7b3dSmrg pixmap->drawable.width, 681428d7b3dSmrg pixmap->drawable.height); 682428d7b3dSmrg 683428d7b3dSmrg uxa_screen->info->done_solid(pixmap); 684428d7b3dSmrg return; 685428d7b3dSmrg 686428d7b3dSmrgfallback: 687428d7b3dSmrg { 688428d7b3dSmrg GCPtr gc; 689428d7b3dSmrg 690428d7b3dSmrg gc = GetScratchGC(pixmap->drawable.depth, screen); 691428d7b3dSmrg if (gc) { 692428d7b3dSmrg xRectangle rect; 693428d7b3dSmrg 694428d7b3dSmrg ValidateGC(&pixmap->drawable, gc); 695428d7b3dSmrg 696428d7b3dSmrg rect.x = 0; 697428d7b3dSmrg rect.y = 0; 698428d7b3dSmrg rect.width = pixmap->drawable.width; 699428d7b3dSmrg rect.height = pixmap->drawable.height; 700428d7b3dSmrg gc->ops->PolyFillRect(&pixmap->drawable, gc, 1, &rect); 701428d7b3dSmrg 702428d7b3dSmrg FreeScratchGC(gc); 703428d7b3dSmrg } 704428d7b3dSmrg } 705428d7b3dSmrg} 706428d7b3dSmrg 707428d7b3dSmrgstatic PicturePtr 708428d7b3dSmrgcreate_white_solid(ScreenPtr screen) 709428d7b3dSmrg{ 710428d7b3dSmrg PicturePtr white, ret = NULL; 711428d7b3dSmrg xRenderColor color; 712428d7b3dSmrg int error; 713428d7b3dSmrg 714428d7b3dSmrg color.red = color.green = color.blue = color.alpha = 0xffff; 715428d7b3dSmrg white = CreateSolidPicture(0, &color, &error); 716428d7b3dSmrg if (white) { 717428d7b3dSmrg ret = uxa_acquire_solid(screen, white->pSourcePict); 718428d7b3dSmrg FreePicture(white, 0); 719428d7b3dSmrg } 720428d7b3dSmrg 721428d7b3dSmrg return ret; 722428d7b3dSmrg} 723428d7b3dSmrg 724428d7b3dSmrgstatic int 725428d7b3dSmrguxa_glyphs_via_mask(CARD8 op, 726428d7b3dSmrg PicturePtr pSrc, 727428d7b3dSmrg PicturePtr pDst, 728428d7b3dSmrg PictFormatPtr maskFormat, 729428d7b3dSmrg INT16 xSrc, INT16 ySrc, 730428d7b3dSmrg int nlist, GlyphListPtr list, GlyphPtr * glyphs) 731428d7b3dSmrg{ 732428d7b3dSmrg ScreenPtr screen = pDst->pDrawable->pScreen; 733428d7b3dSmrg uxa_screen_t *uxa_screen = uxa_get_screen(screen); 734428d7b3dSmrg CARD32 component_alpha; 735428d7b3dSmrg PixmapPtr pixmap, white_pixmap; 736428d7b3dSmrg PicturePtr glyph_atlas, mask, white; 737428d7b3dSmrg int xDst = list->xOff, yDst = list->yOff; 738428d7b3dSmrg int x, y, width, height; 739428d7b3dSmrg int dst_off_x, dst_off_y; 740428d7b3dSmrg int n, error; 741428d7b3dSmrg BoxRec box; 742428d7b3dSmrg 743428d7b3dSmrg uxa_glyph_extents(nlist, list, glyphs, &box); 744428d7b3dSmrg if (box.x2 <= box.x1 || box.y2 <= box.y1) 745428d7b3dSmrg return 0; 746428d7b3dSmrg 747428d7b3dSmrg dst_off_x = box.x1; 748428d7b3dSmrg dst_off_y = box.y1; 749428d7b3dSmrg 750428d7b3dSmrg width = box.x2 - box.x1; 751428d7b3dSmrg height = box.y2 - box.y1; 752428d7b3dSmrg x = -box.x1; 753428d7b3dSmrg y = -box.y1; 754428d7b3dSmrg 755428d7b3dSmrg if (maskFormat->depth == 1) { 756428d7b3dSmrg PictFormatPtr a8Format = 757428d7b3dSmrg PictureMatchFormat(screen, 8, PICT_a8); 758428d7b3dSmrg 759428d7b3dSmrg if (!a8Format) 760428d7b3dSmrg return -1; 761428d7b3dSmrg 762428d7b3dSmrg maskFormat = a8Format; 763428d7b3dSmrg } 764428d7b3dSmrg 765428d7b3dSmrg pixmap = screen->CreatePixmap(screen, width, height, 766428d7b3dSmrg maskFormat->depth, 767428d7b3dSmrg CREATE_PIXMAP_USAGE_SCRATCH); 768428d7b3dSmrg if (!pixmap) 769428d7b3dSmrg return 1; 770428d7b3dSmrg 771428d7b3dSmrg if (!uxa_pixmap_is_offscreen(pixmap)) { 772428d7b3dSmrg screen->DestroyPixmap(pixmap); 773428d7b3dSmrg return -1; 774428d7b3dSmrg } 775428d7b3dSmrg 776428d7b3dSmrg white_pixmap = NULL; 777428d7b3dSmrg white = create_white_solid(screen); 778428d7b3dSmrg if (white) 779428d7b3dSmrg white_pixmap = uxa_get_drawable_pixmap(white->pDrawable); 780428d7b3dSmrg if (!white_pixmap) { 781428d7b3dSmrg if (white) 782428d7b3dSmrg FreePicture(white, 0); 783428d7b3dSmrg screen->DestroyPixmap(pixmap); 784428d7b3dSmrg return -1; 785428d7b3dSmrg } 786428d7b3dSmrg 787428d7b3dSmrg uxa_clear_pixmap(screen, uxa_screen, pixmap); 788428d7b3dSmrg 789428d7b3dSmrg component_alpha = NeedsComponent(maskFormat->format); 790428d7b3dSmrg mask = CreatePicture(0, &pixmap->drawable, 791428d7b3dSmrg maskFormat, CPComponentAlpha, 792428d7b3dSmrg &component_alpha, serverClient, &error); 793428d7b3dSmrg screen->DestroyPixmap(pixmap); 794428d7b3dSmrg 795428d7b3dSmrg if (!mask) { 796428d7b3dSmrg FreePicture(white, 0); 797428d7b3dSmrg return 1; 798428d7b3dSmrg } 799428d7b3dSmrg 800428d7b3dSmrg ValidatePicture(mask); 801428d7b3dSmrg 802428d7b3dSmrg glyph_atlas = NULL; 803428d7b3dSmrg while (nlist--) { 804428d7b3dSmrg x += list->xOff; 805428d7b3dSmrg y += list->yOff; 806428d7b3dSmrg n = list->len; 807428d7b3dSmrg while (n--) { 808428d7b3dSmrg GlyphPtr glyph = *glyphs++; 809428d7b3dSmrg PicturePtr this_atlas; 810428d7b3dSmrg int glyph_x, glyph_y; 811428d7b3dSmrg struct uxa_glyph *priv; 812428d7b3dSmrg 813428d7b3dSmrg if (glyph->info.width == 0 || glyph->info.height == 0) 814428d7b3dSmrg goto next_glyph; 815428d7b3dSmrg 816428d7b3dSmrg priv = uxa_glyph_get_private(glyph); 817428d7b3dSmrg if (priv != NULL) { 818428d7b3dSmrg glyph_x = priv->x; 819428d7b3dSmrg glyph_y = priv->y; 820428d7b3dSmrg this_atlas = priv->cache->picture; 821428d7b3dSmrg } else { 822428d7b3dSmrg if (glyph_atlas) { 823428d7b3dSmrg uxa_screen->info->done_composite(pixmap); 824428d7b3dSmrg glyph_atlas = NULL; 825428d7b3dSmrg } 826428d7b3dSmrg this_atlas = uxa_glyph_cache(screen, glyph, &glyph_x, &glyph_y); 827428d7b3dSmrg if (this_atlas == NULL) { 828428d7b3dSmrg /* no cache for this glyph */ 829428d7b3dSmrg this_atlas = GetGlyphPicture(glyph, screen); 830428d7b3dSmrg glyph_x = glyph_y = 0; 831428d7b3dSmrg } 832428d7b3dSmrg } 833428d7b3dSmrg 834428d7b3dSmrg if (this_atlas != glyph_atlas) { 835428d7b3dSmrg PixmapPtr glyph_pixmap; 836428d7b3dSmrg 837428d7b3dSmrg if (glyph_atlas) 838428d7b3dSmrg uxa_screen->info->done_composite(pixmap); 839428d7b3dSmrg 840428d7b3dSmrg glyph_pixmap = 841428d7b3dSmrg uxa_get_drawable_pixmap(this_atlas->pDrawable); 842428d7b3dSmrg if (!uxa_pixmap_is_offscreen(glyph_pixmap) || 843428d7b3dSmrg !uxa_screen->info->prepare_composite(PictOpAdd, 844428d7b3dSmrg white, this_atlas, mask, 845428d7b3dSmrg white_pixmap, glyph_pixmap, pixmap)) { 846428d7b3dSmrg FreePicture(white, 0); 847428d7b3dSmrg FreePicture(mask, 0); 848428d7b3dSmrg return -1; 849428d7b3dSmrg } 850428d7b3dSmrg 851428d7b3dSmrg glyph_atlas = this_atlas; 852428d7b3dSmrg } 853428d7b3dSmrg 854428d7b3dSmrg uxa_screen->info->composite(pixmap, 855428d7b3dSmrg 0, 0, 856428d7b3dSmrg glyph_x, glyph_y, 857428d7b3dSmrg x - glyph->info.x, 858428d7b3dSmrg y - glyph->info.y, 859428d7b3dSmrg glyph->info.width, 860428d7b3dSmrg glyph->info.height); 861428d7b3dSmrg 862428d7b3dSmrgnext_glyph: 863428d7b3dSmrg x += glyph->info.xOff; 864428d7b3dSmrg y += glyph->info.yOff; 865428d7b3dSmrg } 866428d7b3dSmrg list++; 867428d7b3dSmrg } 868428d7b3dSmrg if (glyph_atlas) 869428d7b3dSmrg uxa_screen->info->done_composite(pixmap); 870428d7b3dSmrg 871428d7b3dSmrg uxa_composite(op, 872428d7b3dSmrg pSrc, mask, pDst, 873428d7b3dSmrg dst_off_x + xSrc - xDst, 874428d7b3dSmrg dst_off_y + ySrc - yDst, 875428d7b3dSmrg 0, 0, 876428d7b3dSmrg dst_off_x, dst_off_y, 877428d7b3dSmrg width, height); 878428d7b3dSmrg 879428d7b3dSmrg FreePicture(white, 0); 880428d7b3dSmrg FreePicture(mask, 0); 881428d7b3dSmrg return 0; 882428d7b3dSmrg} 883428d7b3dSmrg 884428d7b3dSmrgstatic int 885428d7b3dSmrguxa_glyphs_to_dst(CARD8 op, 886428d7b3dSmrg PicturePtr pSrc, 887428d7b3dSmrg PicturePtr pDst, 888428d7b3dSmrg INT16 xSrc, INT16 ySrc, 889428d7b3dSmrg int nlist, GlyphListPtr list, GlyphPtr * glyphs) 890428d7b3dSmrg{ 891428d7b3dSmrg ScreenPtr screen = pDst->pDrawable->pScreen; 892428d7b3dSmrg int x, y, n; 893428d7b3dSmrg 894428d7b3dSmrg xSrc -= list->xOff; 895428d7b3dSmrg ySrc -= list->yOff; 896428d7b3dSmrg x = y = 0; 897428d7b3dSmrg while (nlist--) { 898428d7b3dSmrg x += list->xOff; 899428d7b3dSmrg y += list->yOff; 900428d7b3dSmrg n = list->len; 901428d7b3dSmrg while (n--) { 902428d7b3dSmrg GlyphPtr glyph = *glyphs++; 903428d7b3dSmrg PicturePtr glyph_atlas; 904428d7b3dSmrg int glyph_x, glyph_y; 905428d7b3dSmrg struct uxa_glyph *priv; 906428d7b3dSmrg 907428d7b3dSmrg if (glyph->info.width == 0 || glyph->info.height == 0) 908428d7b3dSmrg goto next_glyph; 909428d7b3dSmrg 910428d7b3dSmrg priv = uxa_glyph_get_private(glyph); 911428d7b3dSmrg if (priv != NULL) { 912428d7b3dSmrg glyph_x = priv->x; 913428d7b3dSmrg glyph_y = priv->y; 914428d7b3dSmrg glyph_atlas = priv->cache->picture; 915428d7b3dSmrg } else { 916428d7b3dSmrg glyph_atlas = uxa_glyph_cache(screen, glyph, &glyph_x, &glyph_y); 917428d7b3dSmrg if (glyph_atlas == NULL) { 918428d7b3dSmrg /* no cache for this glyph */ 919428d7b3dSmrg glyph_atlas = GetGlyphPicture(glyph, screen); 920428d7b3dSmrg glyph_x = glyph_y = 0; 921428d7b3dSmrg } 922428d7b3dSmrg } 923428d7b3dSmrg 924428d7b3dSmrg uxa_composite(op, 925428d7b3dSmrg pSrc, glyph_atlas, pDst, 926428d7b3dSmrg xSrc + x - glyph->info.x, 927428d7b3dSmrg ySrc + y - glyph->info.y, 928428d7b3dSmrg glyph_x, glyph_y, 929428d7b3dSmrg x - glyph->info.x, 930428d7b3dSmrg y - glyph->info.y, 931428d7b3dSmrg glyph->info.width, glyph->info.height); 932428d7b3dSmrg 933428d7b3dSmrgnext_glyph: 934428d7b3dSmrg x += glyph->info.xOff; 935428d7b3dSmrg y += glyph->info.yOff; 936428d7b3dSmrg } 937428d7b3dSmrg list++; 938428d7b3dSmrg } 939428d7b3dSmrg 940428d7b3dSmrg return 0; 941428d7b3dSmrg} 942428d7b3dSmrg 943428d7b3dSmrgstatic Bool 944428d7b3dSmrgis_solid(PicturePtr picture) 945428d7b3dSmrg{ 946428d7b3dSmrg if (picture->pSourcePict) { 947428d7b3dSmrg SourcePict *source = picture->pSourcePict; 948428d7b3dSmrg return source->type == SourcePictTypeSolidFill; 949428d7b3dSmrg } else { 950428d7b3dSmrg return (picture->repeat && 951428d7b3dSmrg picture->pDrawable->width == 1 && 952428d7b3dSmrg picture->pDrawable->height == 1); 953428d7b3dSmrg } 954428d7b3dSmrg} 955428d7b3dSmrg 956428d7b3dSmrgvoid 957428d7b3dSmrguxa_glyphs(CARD8 op, 958428d7b3dSmrg PicturePtr pSrc, 959428d7b3dSmrg PicturePtr pDst, 960428d7b3dSmrg PictFormatPtr maskFormat, 961428d7b3dSmrg INT16 xSrc, INT16 ySrc, 962428d7b3dSmrg int nlist, GlyphListPtr list, GlyphPtr * glyphs) 963428d7b3dSmrg{ 964428d7b3dSmrg ScreenPtr screen = pDst->pDrawable->pScreen; 965428d7b3dSmrg uxa_screen_t *uxa_screen = uxa_get_screen(screen); 966428d7b3dSmrg 967428d7b3dSmrg if (!uxa_screen->info->prepare_composite || 968428d7b3dSmrg uxa_screen->force_fallback || 969428d7b3dSmrg !uxa_drawable_is_offscreen(pDst->pDrawable) || 970428d7b3dSmrg pDst->alphaMap || pSrc->alphaMap || 971428d7b3dSmrg /* XXX we fail to handle (rare) non-solid sources correctly. */ 972428d7b3dSmrg !is_solid(pSrc)) { 973428d7b3dSmrgfallback: 974428d7b3dSmrg uxa_check_glyphs(op, pSrc, pDst, maskFormat, xSrc, ySrc, nlist, list, glyphs); 975428d7b3dSmrg return; 976428d7b3dSmrg } 977428d7b3dSmrg 978428d7b3dSmrg /* basic sanity check */ 979428d7b3dSmrg if (uxa_screen->info->check_composite && 980428d7b3dSmrg !uxa_screen->info->check_composite(op, pSrc, NULL, pDst, 0, 0)) { 981428d7b3dSmrg goto fallback; 982428d7b3dSmrg } 983428d7b3dSmrg 984428d7b3dSmrg ValidatePicture(pSrc); 985428d7b3dSmrg ValidatePicture(pDst); 986428d7b3dSmrg 987428d7b3dSmrg if (!maskFormat) { 988428d7b3dSmrg /* If we don't have a mask format but all the glyphs have the same format, 989428d7b3dSmrg * require ComponentAlpha and don't intersect, use the glyph format as mask 990428d7b3dSmrg * format for the full benefits of the glyph cache. 991428d7b3dSmrg */ 992428d7b3dSmrg if (NeedsComponent(list[0].format->format)) { 993428d7b3dSmrg Bool sameFormat = TRUE; 994428d7b3dSmrg int i; 995428d7b3dSmrg 996428d7b3dSmrg maskFormat = list[0].format; 997428d7b3dSmrg 998428d7b3dSmrg for (i = 0; i < nlist; i++) { 999428d7b3dSmrg if (maskFormat->format != list[i].format->format) { 1000428d7b3dSmrg sameFormat = FALSE; 1001428d7b3dSmrg break; 1002428d7b3dSmrg } 1003428d7b3dSmrg } 1004428d7b3dSmrg 1005428d7b3dSmrg if (!sameFormat || 1006428d7b3dSmrg uxa_glyphs_intersect(nlist, list, glyphs)) 1007428d7b3dSmrg maskFormat = NULL; 1008428d7b3dSmrg } 1009428d7b3dSmrg } 1010428d7b3dSmrg 1011428d7b3dSmrg if (!maskFormat) { 1012428d7b3dSmrg if (uxa_glyphs_to_dst(op, pSrc, pDst, 1013428d7b3dSmrg xSrc, ySrc, 1014428d7b3dSmrg nlist, list, glyphs)) 1015428d7b3dSmrg goto fallback; 1016428d7b3dSmrg } else { 1017428d7b3dSmrg if (uxa_glyphs_via_mask(op, 1018428d7b3dSmrg pSrc, pDst, maskFormat, 1019428d7b3dSmrg xSrc, ySrc, 1020428d7b3dSmrg nlist, list, glyphs)) 1021428d7b3dSmrg goto fallback; 1022428d7b3dSmrg } 1023428d7b3dSmrg} 1024