mipict.c revision 35c4bbdf
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 if (pScreen->SourceValidate) { 298 pScreen->SourceValidate(pDrawable, 0, 0, pDrawable->width, 299 pDrawable->height, pPicture->subWindowMode); 300 } 301} 302 303void 304miCompositeSourceValidate(PicturePtr pPicture) 305{ 306 SourceValidateOnePicture(pPicture); 307 if (pPicture->alphaMap) 308 SourceValidateOnePicture(pPicture->alphaMap); 309} 310 311/* 312 * returns FALSE if the final region is empty. Indistinguishable from 313 * an allocation failure, but rendering ignores those anyways. 314 */ 315 316Bool 317miComputeCompositeRegion(RegionPtr pRegion, 318 PicturePtr pSrc, 319 PicturePtr pMask, 320 PicturePtr pDst, 321 INT16 xSrc, 322 INT16 ySrc, 323 INT16 xMask, 324 INT16 yMask, 325 INT16 xDst, INT16 yDst, CARD16 width, CARD16 height) 326{ 327 328 int v; 329 330 pRegion->extents.x1 = xDst; 331 v = xDst + width; 332 pRegion->extents.x2 = BOUND(v); 333 pRegion->extents.y1 = yDst; 334 v = yDst + height; 335 pRegion->extents.y2 = BOUND(v); 336 pRegion->data = 0; 337 /* Check for empty operation */ 338 if (pRegion->extents.x1 >= pRegion->extents.x2 || 339 pRegion->extents.y1 >= pRegion->extents.y2) { 340 pixman_region_init(pRegion); 341 return FALSE; 342 } 343 /* clip against dst */ 344 if (!miClipPictureReg(pRegion, pDst->pCompositeClip, 0, 0)) { 345 pixman_region_fini(pRegion); 346 return FALSE; 347 } 348 if (pDst->alphaMap) { 349 if (!miClipPictureReg(pRegion, pDst->alphaMap->pCompositeClip, 350 -pDst->alphaOrigin.x, -pDst->alphaOrigin.y)) { 351 pixman_region_fini(pRegion); 352 return FALSE; 353 } 354 } 355 /* clip against src */ 356 if (!miClipPictureSrc(pRegion, pSrc, xDst - xSrc, yDst - ySrc)) { 357 pixman_region_fini(pRegion); 358 return FALSE; 359 } 360 if (pSrc->alphaMap) { 361 if (!miClipPictureSrc(pRegion, pSrc->alphaMap, 362 xDst - (xSrc - pSrc->alphaOrigin.x), 363 yDst - (ySrc - pSrc->alphaOrigin.y))) { 364 pixman_region_fini(pRegion); 365 return FALSE; 366 } 367 } 368 /* clip against mask */ 369 if (pMask) { 370 if (!miClipPictureSrc(pRegion, pMask, xDst - xMask, yDst - yMask)) { 371 pixman_region_fini(pRegion); 372 return FALSE; 373 } 374 if (pMask->alphaMap) { 375 if (!miClipPictureSrc(pRegion, pMask->alphaMap, 376 xDst - (xMask - pMask->alphaOrigin.x), 377 yDst - (yMask - pMask->alphaOrigin.y))) { 378 pixman_region_fini(pRegion); 379 return FALSE; 380 } 381 } 382 } 383 384 miCompositeSourceValidate(pSrc); 385 if (pMask) 386 miCompositeSourceValidate(pMask); 387 388 return TRUE; 389} 390 391void 392miRenderColorToPixel(PictFormatPtr format, xRenderColor * color, CARD32 *pixel) 393{ 394 CARD32 r, g, b, a; 395 miIndexedPtr pIndexed; 396 397 switch (format->type) { 398 case PictTypeDirect: 399 r = color->red >> (16 - Ones(format->direct.redMask)); 400 g = color->green >> (16 - Ones(format->direct.greenMask)); 401 b = color->blue >> (16 - Ones(format->direct.blueMask)); 402 a = color->alpha >> (16 - Ones(format->direct.alphaMask)); 403 r = r << format->direct.red; 404 g = g << format->direct.green; 405 b = b << format->direct.blue; 406 a = a << format->direct.alpha; 407 *pixel = r | g | b | a; 408 break; 409 case PictTypeIndexed: 410 pIndexed = (miIndexedPtr) (format->index.devPrivate); 411 if (pIndexed->color) { 412 r = color->red >> 11; 413 g = color->green >> 11; 414 b = color->blue >> 11; 415 *pixel = miIndexToEnt15(pIndexed, (r << 10) | (g << 5) | b); 416 } 417 else { 418 r = color->red >> 8; 419 g = color->green >> 8; 420 b = color->blue >> 8; 421 *pixel = miIndexToEntY24(pIndexed, (r << 16) | (g << 8) | b); 422 } 423 break; 424 } 425} 426 427static CARD16 428miFillColor(CARD32 pixel, int bits) 429{ 430 while (bits < 16) { 431 pixel |= pixel << bits; 432 bits <<= 1; 433 } 434 return (CARD16) pixel; 435} 436 437Bool 438miIsSolidAlpha(PicturePtr pSrc) 439{ 440 ScreenPtr pScreen; 441 char line[1]; 442 443 if (!pSrc->pDrawable) 444 return FALSE; 445 446 pScreen = pSrc->pDrawable->pScreen; 447 448 /* Alpha-only */ 449 if (PICT_FORMAT_TYPE(pSrc->format) != PICT_TYPE_A) 450 return FALSE; 451 /* repeat */ 452 if (!pSrc->repeat) 453 return FALSE; 454 /* 1x1 */ 455 if (pSrc->pDrawable->width != 1 || pSrc->pDrawable->height != 1) 456 return FALSE; 457 line[0] = 1; 458 (*pScreen->GetImage) (pSrc->pDrawable, 0, 0, 1, 1, ZPixmap, ~0L, line); 459 switch (pSrc->pDrawable->bitsPerPixel) { 460 case 1: 461 return (CARD8) line[0] == 1 || (CARD8) line[0] == 0x80; 462 case 4: 463 return (CARD8) line[0] == 0xf || (CARD8) line[0] == 0xf0; 464 case 8: 465 return (CARD8) line[0] == 0xff; 466 default: 467 return FALSE; 468 } 469} 470 471void 472miRenderPixelToColor(PictFormatPtr format, CARD32 pixel, xRenderColor * color) 473{ 474 CARD32 r, g, b, a; 475 miIndexedPtr pIndexed; 476 477 switch (format->type) { 478 case PictTypeDirect: 479 r = (pixel >> format->direct.red) & format->direct.redMask; 480 g = (pixel >> format->direct.green) & format->direct.greenMask; 481 b = (pixel >> format->direct.blue) & format->direct.blueMask; 482 a = (pixel >> format->direct.alpha) & format->direct.alphaMask; 483 color->red = miFillColor(r, Ones(format->direct.redMask)); 484 color->green = miFillColor(g, Ones(format->direct.greenMask)); 485 color->blue = miFillColor(b, Ones(format->direct.blueMask)); 486 color->alpha = miFillColor(a, Ones(format->direct.alphaMask)); 487 break; 488 case PictTypeIndexed: 489 pIndexed = (miIndexedPtr) (format->index.devPrivate); 490 pixel = pIndexed->rgba[pixel & (MI_MAX_INDEXED - 1)]; 491 r = (pixel >> 16) & 0xff; 492 g = (pixel >> 8) & 0xff; 493 b = (pixel) & 0xff; 494 color->red = miFillColor(r, 8); 495 color->green = miFillColor(g, 8); 496 color->blue = miFillColor(b, 8); 497 color->alpha = 0xffff; 498 break; 499 } 500} 501 502static void 503miTriStrip(CARD8 op, 504 PicturePtr pSrc, 505 PicturePtr pDst, 506 PictFormatPtr maskFormat, 507 INT16 xSrc, INT16 ySrc, int npoints, xPointFixed * points) 508{ 509 xTriangle *tris, *tri; 510 int ntri; 511 512 ntri = npoints - 2; 513 tris = xallocarray(ntri, sizeof(xTriangle)); 514 if (!tris) 515 return; 516 517 for (tri = tris; npoints >= 3; npoints--, points++, tri++) { 518 tri->p1 = points[0]; 519 tri->p2 = points[1]; 520 tri->p3 = points[2]; 521 } 522 CompositeTriangles(op, pSrc, pDst, maskFormat, xSrc, ySrc, ntri, tris); 523 free(tris); 524} 525 526static void 527miTriFan(CARD8 op, 528 PicturePtr pSrc, 529 PicturePtr pDst, 530 PictFormatPtr maskFormat, 531 INT16 xSrc, INT16 ySrc, int npoints, xPointFixed * points) 532{ 533 xTriangle *tris, *tri; 534 xPointFixed *first; 535 int ntri; 536 537 ntri = npoints - 2; 538 tris = xallocarray(ntri, sizeof(xTriangle)); 539 if (!tris) 540 return; 541 542 first = points++; 543 for (tri = tris; npoints >= 3; npoints--, points++, tri++) { 544 tri->p1 = *first; 545 tri->p2 = points[0]; 546 tri->p3 = points[1]; 547 } 548 CompositeTriangles(op, pSrc, pDst, maskFormat, xSrc, ySrc, ntri, tris); 549 free(tris); 550} 551 552Bool 553miPictureInit(ScreenPtr pScreen, PictFormatPtr formats, int nformats) 554{ 555 PictureScreenPtr ps; 556 557 if (!PictureInit(pScreen, formats, nformats)) 558 return FALSE; 559 ps = GetPictureScreen(pScreen); 560 ps->CreatePicture = miCreatePicture; 561 ps->DestroyPicture = miDestroyPicture; 562 ps->ChangePictureClip = miChangePictureClip; 563 ps->DestroyPictureClip = miDestroyPictureClip; 564 ps->ChangePicture = miChangePicture; 565 ps->ValidatePicture = miValidatePicture; 566 ps->InitIndexed = miInitIndexed; 567 ps->CloseIndexed = miCloseIndexed; 568 ps->UpdateIndexed = miUpdateIndexed; 569 ps->ChangePictureTransform = miChangePictureTransform; 570 ps->ChangePictureFilter = miChangePictureFilter; 571 ps->RealizeGlyph = miRealizeGlyph; 572 ps->UnrealizeGlyph = miUnrealizeGlyph; 573 574 /* MI rendering routines */ 575 ps->Composite = 0; /* requires DDX support */ 576 ps->Glyphs = miGlyphs; 577 ps->CompositeRects = miCompositeRects; 578 ps->Trapezoids = 0; 579 ps->Triangles = 0; 580 581 ps->RasterizeTrapezoid = 0; /* requires DDX support */ 582 ps->AddTraps = 0; /* requires DDX support */ 583 ps->AddTriangles = 0; /* requires DDX support */ 584 585 ps->TriStrip = miTriStrip; /* converts call to CompositeTriangles */ 586 ps->TriFan = miTriFan; 587 588 return TRUE; 589} 590