mipict.c revision 9ace9065
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 pPicture->subWindowMode); 391 } 392} 393 394/* 395 * returns FALSE if the final region is empty. Indistinguishable from 396 * an allocation failure, but rendering ignores those anyways. 397 */ 398 399Bool 400miComputeCompositeRegion (RegionPtr pRegion, 401 PicturePtr pSrc, 402 PicturePtr pMask, 403 PicturePtr pDst, 404 INT16 xSrc, 405 INT16 ySrc, 406 INT16 xMask, 407 INT16 yMask, 408 INT16 xDst, 409 INT16 yDst, 410 CARD16 width, 411 CARD16 height) 412{ 413 414 int v; 415 416 pRegion->extents.x1 = xDst; 417 v = xDst + width; 418 pRegion->extents.x2 = BOUND(v); 419 pRegion->extents.y1 = yDst; 420 v = yDst + height; 421 pRegion->extents.y2 = BOUND(v); 422 pRegion->data = 0; 423 /* Check for empty operation */ 424 if (pRegion->extents.x1 >= pRegion->extents.x2 || 425 pRegion->extents.y1 >= pRegion->extents.y2) 426 { 427 pixman_region_init (pRegion); 428 return FALSE; 429 } 430 /* clip against dst */ 431 if (!miClipPictureReg (pRegion, pDst->pCompositeClip, 0, 0)) 432 { 433 pixman_region_fini (pRegion); 434 return FALSE; 435 } 436 if (pDst->alphaMap) 437 { 438 if (!miClipPictureReg (pRegion, pDst->alphaMap->pCompositeClip, 439 -pDst->alphaOrigin.x, 440 -pDst->alphaOrigin.y)) 441 { 442 pixman_region_fini (pRegion); 443 return FALSE; 444 } 445 } 446 /* clip against src */ 447 if (!miClipPictureSrc (pRegion, pSrc, xDst - xSrc, yDst - ySrc)) 448 { 449 pixman_region_fini (pRegion); 450 return FALSE; 451 } 452 if (pSrc->alphaMap) 453 { 454 if (!miClipPictureSrc (pRegion, pSrc->alphaMap, 455 xDst - (xSrc - pSrc->alphaOrigin.x), 456 yDst - (ySrc - pSrc->alphaOrigin.y))) 457 { 458 pixman_region_fini (pRegion); 459 return FALSE; 460 } 461 } 462 /* clip against mask */ 463 if (pMask) 464 { 465 if (!miClipPictureSrc (pRegion, pMask, xDst - xMask, yDst - yMask)) 466 { 467 pixman_region_fini (pRegion); 468 return FALSE; 469 } 470 if (pMask->alphaMap) 471 { 472 if (!miClipPictureSrc (pRegion, pMask->alphaMap, 473 xDst - (xMask - pMask->alphaOrigin.x), 474 yDst - (yMask - pMask->alphaOrigin.y))) 475 { 476 pixman_region_fini (pRegion); 477 return FALSE; 478 } 479 } 480 } 481 482 483 miCompositeSourceValidate (pSrc, xSrc, ySrc, width, height); 484 if (pMask) 485 miCompositeSourceValidate (pMask, xMask, yMask, width, height); 486 487 return TRUE; 488} 489 490void 491miRenderColorToPixel (PictFormatPtr format, 492 xRenderColor *color, 493 CARD32 *pixel) 494{ 495 CARD32 r, g, b, a; 496 miIndexedPtr pIndexed; 497 498 switch (format->type) { 499 case PictTypeDirect: 500 r = color->red >> (16 - Ones (format->direct.redMask)); 501 g = color->green >> (16 - Ones (format->direct.greenMask)); 502 b = color->blue >> (16 - Ones (format->direct.blueMask)); 503 a = color->alpha >> (16 - Ones (format->direct.alphaMask)); 504 r = r << format->direct.red; 505 g = g << format->direct.green; 506 b = b << format->direct.blue; 507 a = a << format->direct.alpha; 508 *pixel = r|g|b|a; 509 break; 510 case PictTypeIndexed: 511 pIndexed = (miIndexedPtr) (format->index.devPrivate); 512 if (pIndexed->color) 513 { 514 r = color->red >> 11; 515 g = color->green >> 11; 516 b = color->blue >> 11; 517 *pixel = miIndexToEnt15 (pIndexed, (r << 10) | (g << 5) | b); 518 } 519 else 520 { 521 r = color->red >> 8; 522 g = color->green >> 8; 523 b = color->blue >> 8; 524 *pixel = miIndexToEntY24 (pIndexed, (r << 16) | (g << 8) | b); 525 } 526 break; 527 } 528} 529 530static CARD16 531miFillColor (CARD32 pixel, int bits) 532{ 533 while (bits < 16) 534 { 535 pixel |= pixel << bits; 536 bits <<= 1; 537 } 538 return (CARD16) pixel; 539} 540 541Bool 542miIsSolidAlpha (PicturePtr pSrc) 543{ 544 ScreenPtr pScreen; 545 char line[1]; 546 547 if (!pSrc->pDrawable) 548 return FALSE; 549 550 pScreen = pSrc->pDrawable->pScreen; 551 552 /* Alpha-only */ 553 if (PICT_FORMAT_TYPE (pSrc->format) != PICT_TYPE_A) 554 return FALSE; 555 /* repeat */ 556 if (!pSrc->repeat) 557 return FALSE; 558 /* 1x1 */ 559 if (pSrc->pDrawable->width != 1 || pSrc->pDrawable->height != 1) 560 return FALSE; 561 line[0] = 1; 562 (*pScreen->GetImage) (pSrc->pDrawable, 0, 0, 1, 1, ZPixmap, ~0L, line); 563 switch (pSrc->pDrawable->bitsPerPixel) { 564 case 1: 565 return (CARD8) line[0] == 1 || (CARD8) line[0] == 0x80; 566 case 4: 567 return (CARD8) line[0] == 0xf || (CARD8) line[0] == 0xf0; 568 case 8: 569 return (CARD8) line[0] == 0xff; 570 default: 571 return FALSE; 572 } 573} 574 575void 576miRenderPixelToColor (PictFormatPtr format, 577 CARD32 pixel, 578 xRenderColor *color) 579{ 580 CARD32 r, g, b, a; 581 miIndexedPtr pIndexed; 582 583 switch (format->type) { 584 case PictTypeDirect: 585 r = (pixel >> format->direct.red) & format->direct.redMask; 586 g = (pixel >> format->direct.green) & format->direct.greenMask; 587 b = (pixel >> format->direct.blue) & format->direct.blueMask; 588 a = (pixel >> format->direct.alpha) & format->direct.alphaMask; 589 color->red = miFillColor (r, Ones (format->direct.redMask)); 590 color->green = miFillColor (g, Ones (format->direct.greenMask)); 591 color->blue = miFillColor (b, Ones (format->direct.blueMask)); 592 color->alpha = miFillColor (a, Ones (format->direct.alphaMask)); 593 break; 594 case PictTypeIndexed: 595 pIndexed = (miIndexedPtr) (format->index.devPrivate); 596 pixel = pIndexed->rgba[pixel & (MI_MAX_INDEXED-1)]; 597 r = (pixel >> 16) & 0xff; 598 g = (pixel >> 8) & 0xff; 599 b = (pixel ) & 0xff; 600 color->red = miFillColor (r, 8); 601 color->green = miFillColor (g, 8); 602 color->blue = miFillColor (b, 8); 603 color->alpha = 0xffff; 604 break; 605 } 606} 607 608Bool 609miPictureInit (ScreenPtr pScreen, PictFormatPtr formats, int nformats) 610{ 611 PictureScreenPtr ps; 612 613 if (!PictureInit (pScreen, formats, nformats)) 614 return FALSE; 615 ps = GetPictureScreen(pScreen); 616 ps->CreatePicture = miCreatePicture; 617 ps->DestroyPicture = miDestroyPicture; 618 ps->ChangePictureClip = miChangePictureClip; 619 ps->DestroyPictureClip = miDestroyPictureClip; 620 ps->ChangePicture = miChangePicture; 621 ps->ValidatePicture = miValidatePicture; 622 ps->InitIndexed = miInitIndexed; 623 ps->CloseIndexed = miCloseIndexed; 624 ps->UpdateIndexed = miUpdateIndexed; 625 ps->ChangePictureTransform = miChangePictureTransform; 626 ps->ChangePictureFilter = miChangePictureFilter; 627 ps->RealizeGlyph = miRealizeGlyph; 628 ps->UnrealizeGlyph = miUnrealizeGlyph; 629 630 /* MI rendering routines */ 631 ps->Composite = 0; /* requires DDX support */ 632 ps->Glyphs = miGlyphs; 633 ps->CompositeRects = miCompositeRects; 634 ps->Trapezoids = miTrapezoids; 635 ps->Triangles = miTriangles; 636 ps->TriStrip = miTriStrip; 637 ps->TriFan = miTriFan; 638 639 ps->RasterizeTrapezoid = 0; /* requires DDX support */ 640 ps->AddTraps = 0; /* requires DDX support */ 641 ps->AddTriangles = 0; /* requires DDX support */ 642 643 return TRUE; 644} 645