mipict.c revision 6747b715
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 36#ifndef __GNUC__ 37#define __inline 38#endif 39 40int 41miCreatePicture (PicturePtr pPicture) 42{ 43 return Success; 44} 45 46void 47miDestroyPicture (PicturePtr pPicture) 48{ 49 if (pPicture->freeCompClip) 50 RegionDestroy(pPicture->pCompositeClip); 51} 52 53void 54miDestroyPictureClip (PicturePtr pPicture) 55{ 56 switch (pPicture->clientClipType) { 57 case CT_NONE: 58 return; 59 case CT_PIXMAP: 60 (*pPicture->pDrawable->pScreen->DestroyPixmap) ((PixmapPtr) (pPicture->clientClip)); 61 break; 62 default: 63 /* 64 * we know we'll never have a list of rectangles, since ChangeClip 65 * immediately turns them into a region 66 */ 67 RegionDestroy(pPicture->clientClip); 68 break; 69 } 70 pPicture->clientClip = NULL; 71 pPicture->clientClipType = CT_NONE; 72} 73 74int 75miChangePictureClip (PicturePtr pPicture, 76 int type, 77 pointer value, 78 int n) 79{ 80 ScreenPtr pScreen = pPicture->pDrawable->pScreen; 81 PictureScreenPtr ps = GetPictureScreen(pScreen); 82 pointer clientClip; 83 int clientClipType; 84 85 switch (type) { 86 case CT_PIXMAP: 87 /* convert the pixmap to a region */ 88 clientClip = (pointer) BitmapToRegion(pScreen, (PixmapPtr) value); 89 if (!clientClip) 90 return BadAlloc; 91 clientClipType = CT_REGION; 92 (*pScreen->DestroyPixmap) ((PixmapPtr) value); 93 break; 94 case CT_REGION: 95 clientClip = value; 96 clientClipType = CT_REGION; 97 break; 98 case CT_NONE: 99 clientClip = 0; 100 clientClipType = CT_NONE; 101 break; 102 default: 103 clientClip = (pointer) RegionFromRects(n, 104 (xRectangle *) value, 105 type); 106 if (!clientClip) 107 return BadAlloc; 108 clientClipType = CT_REGION; 109 free(value); 110 break; 111 } 112 (*ps->DestroyPictureClip) (pPicture); 113 pPicture->clientClip = clientClip; 114 pPicture->clientClipType = clientClipType; 115 pPicture->stateChanges |= CPClipMask; 116 return Success; 117} 118 119void 120miChangePicture (PicturePtr pPicture, 121 Mask mask) 122{ 123 return; 124} 125 126void 127miValidatePicture (PicturePtr pPicture, 128 Mask mask) 129{ 130 DrawablePtr pDrawable = pPicture->pDrawable; 131 132 if ((mask & (CPClipXOrigin|CPClipYOrigin|CPClipMask|CPSubwindowMode)) || 133 (pDrawable->serialNumber != (pPicture->serialNumber & DRAWABLE_SERIAL_BITS))) 134 { 135 if (pDrawable->type == DRAWABLE_WINDOW) 136 { 137 WindowPtr pWin = (WindowPtr) pDrawable; 138 RegionPtr pregWin; 139 Bool freeTmpClip, freeCompClip; 140 141 if (pPicture->subWindowMode == IncludeInferiors) 142 { 143 pregWin = NotClippedByChildren(pWin); 144 freeTmpClip = TRUE; 145 } 146 else 147 { 148 pregWin = &pWin->clipList; 149 freeTmpClip = FALSE; 150 } 151 freeCompClip = pPicture->freeCompClip; 152 153 /* 154 * if there is no client clip, we can get by with just keeping the 155 * pointer we got, and remembering whether or not should destroy 156 * (or maybe re-use) it later. this way, we avoid unnecessary 157 * copying of regions. (this wins especially if many clients clip 158 * by children and have no client clip.) 159 */ 160 if (pPicture->clientClipType == CT_NONE) 161 { 162 if (freeCompClip) 163 RegionDestroy(pPicture->pCompositeClip); 164 pPicture->pCompositeClip = pregWin; 165 pPicture->freeCompClip = freeTmpClip; 166 } 167 else 168 { 169 /* 170 * we need one 'real' region to put into the composite clip. if 171 * pregWin the current composite clip are real, we can get rid of 172 * one. if pregWin is real and the current composite clip isn't, 173 * use pregWin for the composite clip. if the current composite 174 * clip is real and pregWin isn't, use the current composite 175 * clip. if neither is real, create a new region. 176 */ 177 178 RegionTranslate(pPicture->clientClip, 179 pDrawable->x + pPicture->clipOrigin.x, 180 pDrawable->y + pPicture->clipOrigin.y); 181 182 if (freeCompClip) 183 { 184 RegionIntersect(pPicture->pCompositeClip, 185 pregWin, pPicture->clientClip); 186 if (freeTmpClip) 187 RegionDestroy(pregWin); 188 } 189 else if (freeTmpClip) 190 { 191 RegionIntersect(pregWin, pregWin, pPicture->clientClip); 192 pPicture->pCompositeClip = pregWin; 193 } 194 else 195 { 196 pPicture->pCompositeClip = RegionCreate(NullBox, 0); 197 RegionIntersect(pPicture->pCompositeClip, 198 pregWin, pPicture->clientClip); 199 } 200 pPicture->freeCompClip = TRUE; 201 RegionTranslate(pPicture->clientClip, 202 -(pDrawable->x + pPicture->clipOrigin.x), 203 -(pDrawable->y + pPicture->clipOrigin.y)); 204 } 205 } /* end of composite clip for a window */ 206 else 207 { 208 BoxRec pixbounds; 209 210 /* XXX should we translate by drawable.x/y here ? */ 211 /* If you want pixmaps in offscreen memory, yes */ 212 pixbounds.x1 = pDrawable->x; 213 pixbounds.y1 = pDrawable->y; 214 pixbounds.x2 = pDrawable->x + pDrawable->width; 215 pixbounds.y2 = pDrawable->y + pDrawable->height; 216 217 if (pPicture->freeCompClip) 218 { 219 RegionReset(pPicture->pCompositeClip, &pixbounds); 220 } 221 else 222 { 223 pPicture->freeCompClip = TRUE; 224 pPicture->pCompositeClip = RegionCreate(&pixbounds, 1); 225 } 226 227 if (pPicture->clientClipType == CT_REGION) 228 { 229 if(pDrawable->x || pDrawable->y) { 230 RegionTranslate(pPicture->clientClip, 231 pDrawable->x + pPicture->clipOrigin.x, 232 pDrawable->y + pPicture->clipOrigin.y); 233 RegionIntersect(pPicture->pCompositeClip, 234 pPicture->pCompositeClip, pPicture->clientClip); 235 RegionTranslate(pPicture->clientClip, 236 -(pDrawable->x + pPicture->clipOrigin.x), 237 -(pDrawable->y + pPicture->clipOrigin.y)); 238 } else { 239 RegionTranslate(pPicture->pCompositeClip, 240 -pPicture->clipOrigin.x, -pPicture->clipOrigin.y); 241 RegionIntersect(pPicture->pCompositeClip, 242 pPicture->pCompositeClip, pPicture->clientClip); 243 RegionTranslate(pPicture->pCompositeClip, 244 pPicture->clipOrigin.x, pPicture->clipOrigin.y); 245 } 246 } 247 } /* end of composite clip for pixmap */ 248 } 249} 250 251int 252miChangePictureTransform (PicturePtr pPicture, 253 PictTransform *transform) 254{ 255 return Success; 256} 257 258int 259miChangePictureFilter (PicturePtr pPicture, 260 int filter, 261 xFixed *params, 262 int nparams) 263{ 264 return Success; 265} 266 267#define BOUND(v) (INT16) ((v) < MINSHORT ? MINSHORT : (v) > MAXSHORT ? MAXSHORT : (v)) 268 269static inline pixman_bool_t 270miClipPictureReg (pixman_region16_t * pRegion, 271 pixman_region16_t * pClip, 272 int dx, 273 int dy) 274{ 275 if (pixman_region_n_rects(pRegion) == 1 && 276 pixman_region_n_rects(pClip) == 1) 277 { 278 pixman_box16_t * pRbox = pixman_region_rectangles(pRegion, NULL); 279 pixman_box16_t * pCbox = pixman_region_rectangles(pClip, NULL); 280 int v; 281 282 if (pRbox->x1 < (v = pCbox->x1 + dx)) 283 pRbox->x1 = BOUND(v); 284 if (pRbox->x2 > (v = pCbox->x2 + dx)) 285 pRbox->x2 = BOUND(v); 286 if (pRbox->y1 < (v = pCbox->y1 + dy)) 287 pRbox->y1 = BOUND(v); 288 if (pRbox->y2 > (v = pCbox->y2 + dy)) 289 pRbox->y2 = BOUND(v); 290 if (pRbox->x1 >= pRbox->x2 || 291 pRbox->y1 >= pRbox->y2) 292 { 293 pixman_region_init (pRegion); 294 } 295 } 296 else if (!pixman_region_not_empty (pClip)) 297 return FALSE; 298 else 299 { 300 if (dx || dy) 301 pixman_region_translate (pRegion, -dx, -dy); 302 if (!pixman_region_intersect (pRegion, pRegion, pClip)) 303 return FALSE; 304 if (dx || dy) 305 pixman_region_translate(pRegion, dx, dy); 306 } 307 return pixman_region_not_empty(pRegion); 308} 309 310static __inline Bool 311miClipPictureSrc (RegionPtr pRegion, 312 PicturePtr pPicture, 313 int dx, 314 int dy) 315{ 316 if (pPicture->clientClipType != CT_NONE) 317 { 318 Bool result; 319 320 pixman_region_translate ( pPicture->clientClip, 321 pPicture->clipOrigin.x + dx, 322 pPicture->clipOrigin.y + dy); 323 324 result = RegionIntersect(pRegion, pRegion, pPicture->clientClip); 325 326 pixman_region_translate ( pPicture->clientClip, 327 - (pPicture->clipOrigin.x + dx), 328 - (pPicture->clipOrigin.y + dy)); 329 330 if (!result) 331 return FALSE; 332 } 333 return TRUE; 334} 335 336void 337miCompositeSourceValidate (PicturePtr pPicture, 338 INT16 x, 339 INT16 y, 340 CARD16 width, 341 CARD16 height) 342{ 343 DrawablePtr pDrawable = pPicture->pDrawable; 344 ScreenPtr pScreen; 345 346 if (!pDrawable) 347 return; 348 349 pScreen = pDrawable->pScreen; 350 351 if (pScreen->SourceValidate) 352 { 353 if (pPicture->transform) 354 { 355 xPoint points[4]; 356 int i; 357 int xmin, ymin, xmax, ymax; 358 359#define VectorSet(i,_x,_y) { points[i].x = _x; points[i].y = _y; } 360 VectorSet (0, x, y); 361 VectorSet (1, x + width, y); 362 VectorSet (2, x, y + height); 363 VectorSet (3, x + width, y + height); 364 xmin = ymin = 32767; 365 xmax = ymax = -32737; 366 for (i = 0; i < 4; i++) 367 { 368 PictVector t; 369 t.vector[0] = IntToxFixed (points[i].x); 370 t.vector[1] = IntToxFixed (points[i].y); 371 t.vector[2] = xFixed1; 372 if (pixman_transform_point (pPicture->transform, &t)) 373 { 374 int tx = xFixedToInt (t.vector[0]); 375 int ty = xFixedToInt (t.vector[1]); 376 if (tx < xmin) xmin = tx; 377 if (tx > xmax) xmax = tx; 378 if (ty < ymin) ymin = ty; 379 if (ty > ymax) ymax = ty; 380 } 381 } 382 x = xmin; 383 y = ymin; 384 width = xmax - xmin; 385 height = ymax - ymin; 386 } 387 x += pPicture->pDrawable->x; 388 y += pPicture->pDrawable->y; 389 (*pScreen->SourceValidate) (pDrawable, x, y, width, height); 390 } 391} 392 393/* 394 * returns FALSE if the final region is empty. Indistinguishable from 395 * an allocation failure, but rendering ignores those anyways. 396 */ 397 398Bool 399miComputeCompositeRegion (RegionPtr pRegion, 400 PicturePtr pSrc, 401 PicturePtr pMask, 402 PicturePtr pDst, 403 INT16 xSrc, 404 INT16 ySrc, 405 INT16 xMask, 406 INT16 yMask, 407 INT16 xDst, 408 INT16 yDst, 409 CARD16 width, 410 CARD16 height) 411{ 412 413 int v; 414 415 pRegion->extents.x1 = xDst; 416 v = xDst + width; 417 pRegion->extents.x2 = BOUND(v); 418 pRegion->extents.y1 = yDst; 419 v = yDst + height; 420 pRegion->extents.y2 = BOUND(v); 421 pRegion->data = 0; 422 /* Check for empty operation */ 423 if (pRegion->extents.x1 >= pRegion->extents.x2 || 424 pRegion->extents.y1 >= pRegion->extents.y2) 425 { 426 pixman_region_init (pRegion); 427 return FALSE; 428 } 429 /* clip against dst */ 430 if (!miClipPictureReg (pRegion, pDst->pCompositeClip, 0, 0)) 431 { 432 pixman_region_fini (pRegion); 433 return FALSE; 434 } 435 if (pDst->alphaMap) 436 { 437 if (!miClipPictureReg (pRegion, pDst->alphaMap->pCompositeClip, 438 -pDst->alphaOrigin.x, 439 -pDst->alphaOrigin.y)) 440 { 441 pixman_region_fini (pRegion); 442 return FALSE; 443 } 444 } 445 /* clip against src */ 446 if (!miClipPictureSrc (pRegion, pSrc, xDst - xSrc, yDst - ySrc)) 447 { 448 pixman_region_fini (pRegion); 449 return FALSE; 450 } 451 if (pSrc->alphaMap) 452 { 453 if (!miClipPictureSrc (pRegion, pSrc->alphaMap, 454 xDst - (xSrc - pSrc->alphaOrigin.x), 455 yDst - (ySrc - pSrc->alphaOrigin.y))) 456 { 457 pixman_region_fini (pRegion); 458 return FALSE; 459 } 460 } 461 /* clip against mask */ 462 if (pMask) 463 { 464 if (!miClipPictureSrc (pRegion, pMask, xDst - xMask, yDst - yMask)) 465 { 466 pixman_region_fini (pRegion); 467 return FALSE; 468 } 469 if (pMask->alphaMap) 470 { 471 if (!miClipPictureSrc (pRegion, pMask->alphaMap, 472 xDst - (xMask - pMask->alphaOrigin.x), 473 yDst - (yMask - pMask->alphaOrigin.y))) 474 { 475 pixman_region_fini (pRegion); 476 return FALSE; 477 } 478 } 479 } 480 481 482 miCompositeSourceValidate (pSrc, xSrc, ySrc, width, height); 483 if (pMask) 484 miCompositeSourceValidate (pMask, xMask, yMask, width, height); 485 486 return TRUE; 487} 488 489void 490miRenderColorToPixel (PictFormatPtr format, 491 xRenderColor *color, 492 CARD32 *pixel) 493{ 494 CARD32 r, g, b, a; 495 miIndexedPtr pIndexed; 496 497 switch (format->type) { 498 case PictTypeDirect: 499 r = color->red >> (16 - Ones (format->direct.redMask)); 500 g = color->green >> (16 - Ones (format->direct.greenMask)); 501 b = color->blue >> (16 - Ones (format->direct.blueMask)); 502 a = color->alpha >> (16 - Ones (format->direct.alphaMask)); 503 r = r << format->direct.red; 504 g = g << format->direct.green; 505 b = b << format->direct.blue; 506 a = a << format->direct.alpha; 507 *pixel = r|g|b|a; 508 break; 509 case PictTypeIndexed: 510 pIndexed = (miIndexedPtr) (format->index.devPrivate); 511 if (pIndexed->color) 512 { 513 r = color->red >> 11; 514 g = color->green >> 11; 515 b = color->blue >> 11; 516 *pixel = miIndexToEnt15 (pIndexed, (r << 10) | (g << 5) | b); 517 } 518 else 519 { 520 r = color->red >> 8; 521 g = color->green >> 8; 522 b = color->blue >> 8; 523 *pixel = miIndexToEntY24 (pIndexed, (r << 16) | (g << 8) | b); 524 } 525 break; 526 } 527} 528 529static CARD16 530miFillColor (CARD32 pixel, int bits) 531{ 532 while (bits < 16) 533 { 534 pixel |= pixel << bits; 535 bits <<= 1; 536 } 537 return (CARD16) pixel; 538} 539 540Bool 541miIsSolidAlpha (PicturePtr pSrc) 542{ 543 ScreenPtr pScreen; 544 char line[1]; 545 546 if (!pSrc->pDrawable) 547 return FALSE; 548 549 pScreen = pSrc->pDrawable->pScreen; 550 551 /* Alpha-only */ 552 if (PICT_FORMAT_TYPE (pSrc->format) != PICT_TYPE_A) 553 return FALSE; 554 /* repeat */ 555 if (!pSrc->repeat) 556 return FALSE; 557 /* 1x1 */ 558 if (pSrc->pDrawable->width != 1 || pSrc->pDrawable->height != 1) 559 return FALSE; 560 line[0] = 1; 561 (*pScreen->GetImage) (pSrc->pDrawable, 0, 0, 1, 1, ZPixmap, ~0L, line); 562 switch (pSrc->pDrawable->bitsPerPixel) { 563 case 1: 564 return (CARD8) line[0] == 1 || (CARD8) line[0] == 0x80; 565 case 4: 566 return (CARD8) line[0] == 0xf || (CARD8) line[0] == 0xf0; 567 case 8: 568 return (CARD8) line[0] == 0xff; 569 default: 570 return FALSE; 571 } 572} 573 574void 575miRenderPixelToColor (PictFormatPtr format, 576 CARD32 pixel, 577 xRenderColor *color) 578{ 579 CARD32 r, g, b, a; 580 miIndexedPtr pIndexed; 581 582 switch (format->type) { 583 case PictTypeDirect: 584 r = (pixel >> format->direct.red) & format->direct.redMask; 585 g = (pixel >> format->direct.green) & format->direct.greenMask; 586 b = (pixel >> format->direct.blue) & format->direct.blueMask; 587 a = (pixel >> format->direct.alpha) & format->direct.alphaMask; 588 color->red = miFillColor (r, Ones (format->direct.redMask)); 589 color->green = miFillColor (g, Ones (format->direct.greenMask)); 590 color->blue = miFillColor (b, Ones (format->direct.blueMask)); 591 color->alpha = miFillColor (a, Ones (format->direct.alphaMask)); 592 break; 593 case PictTypeIndexed: 594 pIndexed = (miIndexedPtr) (format->index.devPrivate); 595 pixel = pIndexed->rgba[pixel & (MI_MAX_INDEXED-1)]; 596 r = (pixel >> 16) & 0xff; 597 g = (pixel >> 8) & 0xff; 598 b = (pixel ) & 0xff; 599 color->red = miFillColor (r, 8); 600 color->green = miFillColor (g, 8); 601 color->blue = miFillColor (b, 8); 602 color->alpha = 0xffff; 603 break; 604 } 605} 606 607Bool 608miPictureInit (ScreenPtr pScreen, PictFormatPtr formats, int nformats) 609{ 610 PictureScreenPtr ps; 611 612 if (!PictureInit (pScreen, formats, nformats)) 613 return FALSE; 614 ps = GetPictureScreen(pScreen); 615 ps->CreatePicture = miCreatePicture; 616 ps->DestroyPicture = miDestroyPicture; 617 ps->ChangePictureClip = miChangePictureClip; 618 ps->DestroyPictureClip = miDestroyPictureClip; 619 ps->ChangePicture = miChangePicture; 620 ps->ValidatePicture = miValidatePicture; 621 ps->InitIndexed = miInitIndexed; 622 ps->CloseIndexed = miCloseIndexed; 623 ps->UpdateIndexed = miUpdateIndexed; 624 ps->ChangePictureTransform = miChangePictureTransform; 625 ps->ChangePictureFilter = miChangePictureFilter; 626 ps->RealizeGlyph = miRealizeGlyph; 627 ps->UnrealizeGlyph = miUnrealizeGlyph; 628 629 /* MI rendering routines */ 630 ps->Composite = 0; /* requires DDX support */ 631 ps->Glyphs = miGlyphs; 632 ps->CompositeRects = miCompositeRects; 633 ps->Trapezoids = miTrapezoids; 634 ps->Triangles = miTriangles; 635 ps->TriStrip = miTriStrip; 636 ps->TriFan = miTriFan; 637 638 ps->RasterizeTrapezoid = 0; /* requires DDX support */ 639 ps->AddTraps = 0; /* requires DDX support */ 640 ps->AddTriangles = 0; /* requires DDX support */ 641 642 return TRUE; 643} 644