mipict.c revision ed6184df
1/* 2 * 3 * Copyright © 1999 Keith Packard 4 * 5 * Permission to use, copy, modify, distribute, and sell this software and its 6 * documentation for any purpose is hereby granted without fee, provided that 7 * the above copyright notice appear in all copies and that both that 8 * copyright notice and this permission notice appear in supporting 9 * documentation, and that the name of Keith Packard not be used in 10 * advertising or publicity pertaining to distribution of the software without 11 * specific, written prior permission. Keith Packard makes no 12 * representations about the suitability of this software for any purpose. It 13 * is provided "as is" without express or implied warranty. 14 * 15 * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 16 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 17 * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR 18 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 19 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 20 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 21 * PERFORMANCE OF THIS SOFTWARE. 22 */ 23 24#ifdef HAVE_DIX_CONFIG_H 25#include <dix-config.h> 26#endif 27 28#include "scrnintstr.h" 29#include "gcstruct.h" 30#include "pixmapstr.h" 31#include "windowstr.h" 32#include "mi.h" 33#include "picturestr.h" 34#include "mipict.h" 35 36int 37miCreatePicture(PicturePtr pPicture) 38{ 39 return Success; 40} 41 42void 43miDestroyPicture(PicturePtr pPicture) 44{ 45 if (pPicture->freeCompClip) 46 RegionDestroy(pPicture->pCompositeClip); 47} 48 49static void 50miDestroyPictureClip(PicturePtr pPicture) 51{ 52 if (pPicture->clientClip) 53 RegionDestroy(pPicture->clientClip); 54 pPicture->clientClip = NULL; 55} 56 57static int 58miChangePictureClip(PicturePtr pPicture, int type, void *value, int n) 59{ 60 ScreenPtr pScreen = pPicture->pDrawable->pScreen; 61 PictureScreenPtr ps = GetPictureScreen(pScreen); 62 RegionPtr clientClip; 63 64 switch (type) { 65 case CT_PIXMAP: 66 /* convert the pixmap to a region */ 67 clientClip = BitmapToRegion(pScreen, (PixmapPtr) value); 68 if (!clientClip) 69 return BadAlloc; 70 (*pScreen->DestroyPixmap) ((PixmapPtr) value); 71 break; 72 case CT_REGION: 73 clientClip = value; 74 break; 75 case CT_NONE: 76 clientClip = 0; 77 break; 78 default: 79 clientClip = RegionFromRects(n, (xRectangle *) value, type); 80 if (!clientClip) 81 return BadAlloc; 82 free(value); 83 break; 84 } 85 (*ps->DestroyPictureClip) (pPicture); 86 pPicture->clientClip = clientClip; 87 pPicture->stateChanges |= CPClipMask; 88 return Success; 89} 90 91static void 92miChangePicture(PicturePtr pPicture, Mask mask) 93{ 94 return; 95} 96 97static void 98miValidatePicture(PicturePtr pPicture, Mask mask) 99{ 100 DrawablePtr pDrawable = pPicture->pDrawable; 101 102 if ((mask & (CPClipXOrigin | CPClipYOrigin | CPClipMask | CPSubwindowMode)) 103 || (pDrawable->serialNumber != 104 (pPicture->serialNumber & DRAWABLE_SERIAL_BITS))) { 105 if (pDrawable->type == DRAWABLE_WINDOW) { 106 WindowPtr pWin = (WindowPtr) pDrawable; 107 RegionPtr pregWin; 108 Bool freeTmpClip, freeCompClip; 109 110 if (pPicture->subWindowMode == IncludeInferiors) { 111 pregWin = NotClippedByChildren(pWin); 112 freeTmpClip = TRUE; 113 } 114 else { 115 pregWin = &pWin->clipList; 116 freeTmpClip = FALSE; 117 } 118 freeCompClip = pPicture->freeCompClip; 119 120 /* 121 * if there is no client clip, we can get by with just keeping the 122 * pointer we got, and remembering whether or not should destroy 123 * (or maybe re-use) it later. this way, we avoid unnecessary 124 * copying of regions. (this wins especially if many clients clip 125 * by children and have no client clip.) 126 */ 127 if (!pPicture->clientClip) { 128 if (freeCompClip) 129 RegionDestroy(pPicture->pCompositeClip); 130 pPicture->pCompositeClip = pregWin; 131 pPicture->freeCompClip = freeTmpClip; 132 } 133 else { 134 /* 135 * we need one 'real' region to put into the composite clip. if 136 * pregWin the current composite clip are real, we can get rid of 137 * one. if pregWin is real and the current composite clip isn't, 138 * use pregWin for the composite clip. if the current composite 139 * clip is real and pregWin isn't, use the current composite 140 * clip. if neither is real, create a new region. 141 */ 142 143 RegionTranslate(pPicture->clientClip, 144 pDrawable->x + pPicture->clipOrigin.x, 145 pDrawable->y + pPicture->clipOrigin.y); 146 147 if (freeCompClip) { 148 RegionIntersect(pPicture->pCompositeClip, 149 pregWin, pPicture->clientClip); 150 if (freeTmpClip) 151 RegionDestroy(pregWin); 152 } 153 else if (freeTmpClip) { 154 RegionIntersect(pregWin, pregWin, pPicture->clientClip); 155 pPicture->pCompositeClip = pregWin; 156 } 157 else { 158 pPicture->pCompositeClip = RegionCreate(NullBox, 0); 159 RegionIntersect(pPicture->pCompositeClip, 160 pregWin, pPicture->clientClip); 161 } 162 pPicture->freeCompClip = TRUE; 163 RegionTranslate(pPicture->clientClip, 164 -(pDrawable->x + pPicture->clipOrigin.x), 165 -(pDrawable->y + pPicture->clipOrigin.y)); 166 } 167 } /* end of composite clip for a window */ 168 else { 169 BoxRec pixbounds; 170 171 /* XXX should we translate by drawable.x/y here ? */ 172 /* If you want pixmaps in offscreen memory, yes */ 173 pixbounds.x1 = pDrawable->x; 174 pixbounds.y1 = pDrawable->y; 175 pixbounds.x2 = pDrawable->x + pDrawable->width; 176 pixbounds.y2 = pDrawable->y + pDrawable->height; 177 178 if (pPicture->freeCompClip) { 179 RegionReset(pPicture->pCompositeClip, &pixbounds); 180 } 181 else { 182 pPicture->freeCompClip = TRUE; 183 pPicture->pCompositeClip = RegionCreate(&pixbounds, 1); 184 } 185 186 if (pPicture->clientClip) { 187 if (pDrawable->x || pDrawable->y) { 188 RegionTranslate(pPicture->clientClip, 189 pDrawable->x + pPicture->clipOrigin.x, 190 pDrawable->y + pPicture->clipOrigin.y); 191 RegionIntersect(pPicture->pCompositeClip, 192 pPicture->pCompositeClip, 193 pPicture->clientClip); 194 RegionTranslate(pPicture->clientClip, 195 -(pDrawable->x + pPicture->clipOrigin.x), 196 -(pDrawable->y + pPicture->clipOrigin.y)); 197 } 198 else { 199 RegionTranslate(pPicture->pCompositeClip, 200 -pPicture->clipOrigin.x, 201 -pPicture->clipOrigin.y); 202 RegionIntersect(pPicture->pCompositeClip, 203 pPicture->pCompositeClip, 204 pPicture->clientClip); 205 RegionTranslate(pPicture->pCompositeClip, 206 pPicture->clipOrigin.x, 207 pPicture->clipOrigin.y); 208 } 209 } 210 } /* end of composite clip for pixmap */ 211 } 212} 213 214static int 215miChangePictureTransform(PicturePtr pPicture, PictTransform * transform) 216{ 217 return Success; 218} 219 220static int 221miChangePictureFilter(PicturePtr pPicture, 222 int filter, xFixed * params, int nparams) 223{ 224 return Success; 225} 226 227#define BOUND(v) (INT16) ((v) < MINSHORT ? MINSHORT : (v) > MAXSHORT ? MAXSHORT : (v)) 228 229static inline pixman_bool_t 230miClipPictureReg(pixman_region16_t * pRegion, 231 pixman_region16_t * pClip, int dx, int dy) 232{ 233 if (pixman_region_n_rects(pRegion) == 1 && 234 pixman_region_n_rects(pClip) == 1) { 235 pixman_box16_t *pRbox = pixman_region_rectangles(pRegion, NULL); 236 pixman_box16_t *pCbox = pixman_region_rectangles(pClip, NULL); 237 int v; 238 239 if (pRbox->x1 < (v = pCbox->x1 + dx)) 240 pRbox->x1 = BOUND(v); 241 if (pRbox->x2 > (v = pCbox->x2 + dx)) 242 pRbox->x2 = BOUND(v); 243 if (pRbox->y1 < (v = pCbox->y1 + dy)) 244 pRbox->y1 = BOUND(v); 245 if (pRbox->y2 > (v = pCbox->y2 + dy)) 246 pRbox->y2 = BOUND(v); 247 if (pRbox->x1 >= pRbox->x2 || pRbox->y1 >= pRbox->y2) { 248 pixman_region_init(pRegion); 249 } 250 } 251 else if (!pixman_region_not_empty(pClip)) 252 return FALSE; 253 else { 254 if (dx || dy) 255 pixman_region_translate(pRegion, -dx, -dy); 256 if (!pixman_region_intersect(pRegion, pRegion, pClip)) 257 return FALSE; 258 if (dx || dy) 259 pixman_region_translate(pRegion, dx, dy); 260 } 261 return pixman_region_not_empty(pRegion); 262} 263 264static inline Bool 265miClipPictureSrc(RegionPtr pRegion, PicturePtr pPicture, int dx, int dy) 266{ 267 if (pPicture->clientClip) { 268 Bool result; 269 270 pixman_region_translate(pPicture->clientClip, 271 pPicture->clipOrigin.x + dx, 272 pPicture->clipOrigin.y + dy); 273 274 result = RegionIntersect(pRegion, pRegion, pPicture->clientClip); 275 276 pixman_region_translate(pPicture->clientClip, 277 -(pPicture->clipOrigin.x + dx), 278 -(pPicture->clipOrigin.y + dy)); 279 280 if (!result) 281 return FALSE; 282 } 283 return TRUE; 284} 285 286static void 287SourceValidateOnePicture(PicturePtr pPicture) 288{ 289 DrawablePtr pDrawable = pPicture->pDrawable; 290 ScreenPtr pScreen; 291 292 if (!pDrawable) 293 return; 294 295 pScreen = pDrawable->pScreen; 296 297 pScreen->SourceValidate(pDrawable, 0, 0, pDrawable->width, 298 pDrawable->height, pPicture->subWindowMode); 299} 300 301void 302miCompositeSourceValidate(PicturePtr pPicture) 303{ 304 SourceValidateOnePicture(pPicture); 305 if (pPicture->alphaMap) 306 SourceValidateOnePicture(pPicture->alphaMap); 307} 308 309/* 310 * returns FALSE if the final region is empty. Indistinguishable from 311 * an allocation failure, but rendering ignores those anyways. 312 */ 313 314Bool 315miComputeCompositeRegion(RegionPtr pRegion, 316 PicturePtr pSrc, 317 PicturePtr pMask, 318 PicturePtr pDst, 319 INT16 xSrc, 320 INT16 ySrc, 321 INT16 xMask, 322 INT16 yMask, 323 INT16 xDst, INT16 yDst, CARD16 width, CARD16 height) 324{ 325 326 int v; 327 328 pRegion->extents.x1 = xDst; 329 v = xDst + width; 330 pRegion->extents.x2 = BOUND(v); 331 pRegion->extents.y1 = yDst; 332 v = yDst + height; 333 pRegion->extents.y2 = BOUND(v); 334 pRegion->data = 0; 335 /* Check for empty operation */ 336 if (pRegion->extents.x1 >= pRegion->extents.x2 || 337 pRegion->extents.y1 >= pRegion->extents.y2) { 338 pixman_region_init(pRegion); 339 return FALSE; 340 } 341 /* clip against dst */ 342 if (!miClipPictureReg(pRegion, pDst->pCompositeClip, 0, 0)) { 343 pixman_region_fini(pRegion); 344 return FALSE; 345 } 346 if (pDst->alphaMap) { 347 if (!miClipPictureReg(pRegion, pDst->alphaMap->pCompositeClip, 348 -pDst->alphaOrigin.x, -pDst->alphaOrigin.y)) { 349 pixman_region_fini(pRegion); 350 return FALSE; 351 } 352 } 353 /* clip against src */ 354 if (!miClipPictureSrc(pRegion, pSrc, xDst - xSrc, yDst - ySrc)) { 355 pixman_region_fini(pRegion); 356 return FALSE; 357 } 358 if (pSrc->alphaMap) { 359 if (!miClipPictureSrc(pRegion, pSrc->alphaMap, 360 xDst - (xSrc - pSrc->alphaOrigin.x), 361 yDst - (ySrc - pSrc->alphaOrigin.y))) { 362 pixman_region_fini(pRegion); 363 return FALSE; 364 } 365 } 366 /* clip against mask */ 367 if (pMask) { 368 if (!miClipPictureSrc(pRegion, pMask, xDst - xMask, yDst - yMask)) { 369 pixman_region_fini(pRegion); 370 return FALSE; 371 } 372 if (pMask->alphaMap) { 373 if (!miClipPictureSrc(pRegion, pMask->alphaMap, 374 xDst - (xMask - pMask->alphaOrigin.x), 375 yDst - (yMask - pMask->alphaOrigin.y))) { 376 pixman_region_fini(pRegion); 377 return FALSE; 378 } 379 } 380 } 381 382 miCompositeSourceValidate(pSrc); 383 if (pMask) 384 miCompositeSourceValidate(pMask); 385 386 return TRUE; 387} 388 389void 390miRenderColorToPixel(PictFormatPtr format, xRenderColor * color, CARD32 *pixel) 391{ 392 CARD32 r, g, b, a; 393 miIndexedPtr pIndexed; 394 395 switch (format->type) { 396 case PictTypeDirect: 397 r = color->red >> (16 - Ones(format->direct.redMask)); 398 g = color->green >> (16 - Ones(format->direct.greenMask)); 399 b = color->blue >> (16 - Ones(format->direct.blueMask)); 400 a = color->alpha >> (16 - Ones(format->direct.alphaMask)); 401 r = r << format->direct.red; 402 g = g << format->direct.green; 403 b = b << format->direct.blue; 404 a = a << format->direct.alpha; 405 *pixel = r | g | b | a; 406 break; 407 case PictTypeIndexed: 408 pIndexed = (miIndexedPtr) (format->index.devPrivate); 409 if (pIndexed->color) { 410 r = color->red >> 11; 411 g = color->green >> 11; 412 b = color->blue >> 11; 413 *pixel = miIndexToEnt15(pIndexed, (r << 10) | (g << 5) | b); 414 } 415 else { 416 r = color->red >> 8; 417 g = color->green >> 8; 418 b = color->blue >> 8; 419 *pixel = miIndexToEntY24(pIndexed, (r << 16) | (g << 8) | b); 420 } 421 break; 422 } 423} 424 425static CARD16 426miFillColor(CARD32 pixel, int bits) 427{ 428 while (bits < 16) { 429 pixel |= pixel << bits; 430 bits <<= 1; 431 } 432 return (CARD16) pixel; 433} 434 435Bool 436miIsSolidAlpha(PicturePtr pSrc) 437{ 438 ScreenPtr pScreen; 439 char line[1]; 440 441 if (!pSrc->pDrawable) 442 return FALSE; 443 444 pScreen = pSrc->pDrawable->pScreen; 445 446 /* Alpha-only */ 447 if (PICT_FORMAT_TYPE(pSrc->format) != PICT_TYPE_A) 448 return FALSE; 449 /* repeat */ 450 if (!pSrc->repeat) 451 return FALSE; 452 /* 1x1 */ 453 if (pSrc->pDrawable->width != 1 || pSrc->pDrawable->height != 1) 454 return FALSE; 455 line[0] = 1; 456 (*pScreen->GetImage) (pSrc->pDrawable, 0, 0, 1, 1, ZPixmap, ~0L, line); 457 switch (pSrc->pDrawable->bitsPerPixel) { 458 case 1: 459 return (CARD8) line[0] == 1 || (CARD8) line[0] == 0x80; 460 case 4: 461 return (CARD8) line[0] == 0xf || (CARD8) line[0] == 0xf0; 462 case 8: 463 return (CARD8) line[0] == 0xff; 464 default: 465 return FALSE; 466 } 467} 468 469void 470miRenderPixelToColor(PictFormatPtr format, CARD32 pixel, xRenderColor * color) 471{ 472 CARD32 r, g, b, a; 473 miIndexedPtr pIndexed; 474 475 switch (format->type) { 476 case PictTypeDirect: 477 r = (pixel >> format->direct.red) & format->direct.redMask; 478 g = (pixel >> format->direct.green) & format->direct.greenMask; 479 b = (pixel >> format->direct.blue) & format->direct.blueMask; 480 a = (pixel >> format->direct.alpha) & format->direct.alphaMask; 481 color->red = miFillColor(r, Ones(format->direct.redMask)); 482 color->green = miFillColor(g, Ones(format->direct.greenMask)); 483 color->blue = miFillColor(b, Ones(format->direct.blueMask)); 484 color->alpha = miFillColor(a, Ones(format->direct.alphaMask)); 485 break; 486 case PictTypeIndexed: 487 pIndexed = (miIndexedPtr) (format->index.devPrivate); 488 pixel = pIndexed->rgba[pixel & (MI_MAX_INDEXED - 1)]; 489 r = (pixel >> 16) & 0xff; 490 g = (pixel >> 8) & 0xff; 491 b = (pixel) & 0xff; 492 color->red = miFillColor(r, 8); 493 color->green = miFillColor(g, 8); 494 color->blue = miFillColor(b, 8); 495 color->alpha = 0xffff; 496 break; 497 } 498} 499 500static void 501miTriStrip(CARD8 op, 502 PicturePtr pSrc, 503 PicturePtr pDst, 504 PictFormatPtr maskFormat, 505 INT16 xSrc, INT16 ySrc, int npoints, xPointFixed * points) 506{ 507 xTriangle *tris, *tri; 508 int ntri; 509 510 ntri = npoints - 2; 511 tris = xallocarray(ntri, sizeof(xTriangle)); 512 if (!tris) 513 return; 514 515 for (tri = tris; npoints >= 3; npoints--, points++, tri++) { 516 tri->p1 = points[0]; 517 tri->p2 = points[1]; 518 tri->p3 = points[2]; 519 } 520 CompositeTriangles(op, pSrc, pDst, maskFormat, xSrc, ySrc, ntri, tris); 521 free(tris); 522} 523 524static void 525miTriFan(CARD8 op, 526 PicturePtr pSrc, 527 PicturePtr pDst, 528 PictFormatPtr maskFormat, 529 INT16 xSrc, INT16 ySrc, int npoints, xPointFixed * points) 530{ 531 xTriangle *tris, *tri; 532 xPointFixed *first; 533 int ntri; 534 535 ntri = npoints - 2; 536 tris = xallocarray(ntri, sizeof(xTriangle)); 537 if (!tris) 538 return; 539 540 first = points++; 541 for (tri = tris; npoints >= 3; npoints--, points++, tri++) { 542 tri->p1 = *first; 543 tri->p2 = points[0]; 544 tri->p3 = points[1]; 545 } 546 CompositeTriangles(op, pSrc, pDst, maskFormat, xSrc, ySrc, ntri, tris); 547 free(tris); 548} 549 550Bool 551miPictureInit(ScreenPtr pScreen, PictFormatPtr formats, int nformats) 552{ 553 PictureScreenPtr ps; 554 555 if (!PictureInit(pScreen, formats, nformats)) 556 return FALSE; 557 ps = GetPictureScreen(pScreen); 558 ps->CreatePicture = miCreatePicture; 559 ps->DestroyPicture = miDestroyPicture; 560 ps->ChangePictureClip = miChangePictureClip; 561 ps->DestroyPictureClip = miDestroyPictureClip; 562 ps->ChangePicture = miChangePicture; 563 ps->ValidatePicture = miValidatePicture; 564 ps->InitIndexed = miInitIndexed; 565 ps->CloseIndexed = miCloseIndexed; 566 ps->UpdateIndexed = miUpdateIndexed; 567 ps->ChangePictureTransform = miChangePictureTransform; 568 ps->ChangePictureFilter = miChangePictureFilter; 569 ps->RealizeGlyph = miRealizeGlyph; 570 ps->UnrealizeGlyph = miUnrealizeGlyph; 571 572 /* MI rendering routines */ 573 ps->Composite = 0; /* requires DDX support */ 574 ps->Glyphs = miGlyphs; 575 ps->CompositeRects = miCompositeRects; 576 ps->Trapezoids = 0; 577 ps->Triangles = 0; 578 579 ps->RasterizeTrapezoid = 0; /* requires DDX support */ 580 ps->AddTraps = 0; /* requires DDX support */ 581 ps->AddTriangles = 0; /* requires DDX support */ 582 583 ps->TriStrip = miTriStrip; /* converts call to CompositeTriangles */ 584 ps->TriFan = miTriFan; 585 586 return TRUE; 587} 588