1 /************************************************************** 2 * 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, 14 * software distributed under the License is distributed on an 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 * KIND, either express or implied. See the License for the 17 * specific language governing permissions and limitations 18 * under the License. 19 * 20 *************************************************************/ 21 22 23 24 // MARKER(update_precomp.py): autogen include statement, do not remove 25 #include "precompiled_vcl.hxx" 26 27 #include <stdio.h> 28 #include <poll.h> 29 30 #include "vcl/salbtype.hxx" 31 32 #include "unx/salunx.h" 33 #include "unx/saldata.hxx" 34 #include "unx/saldisp.hxx" 35 #include "unx/salbmp.h" 36 #include "unx/salgdi.h" 37 #include "unx/salframe.h" 38 #include "unx/salvd.h" 39 #include "xrender_peer.hxx" 40 41 #include "printergfx.hxx" 42 43 #include "vcl/bmpacc.hxx" 44 45 #undef SALGDI2_TESTTRANS 46 47 // -=-= debugging =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= 48 // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= 49 #if 0 50 51 static void sal_PrintImage( char *s, XImage*p ) 52 { 53 fprintf( stderr, "%s %d %d %d\n", s, p->depth, p->width, p->height ); 54 int nW = Min( 64, p->width*p->bits_per_pixel >> 3 ); 55 for( int i = 0; i < Min( 16, p->height ); i++ ) 56 { 57 for( int j = 0; j < nW; j++ ) 58 fprintf( stderr, "%02X", (UINT8)p->data[i*p->bytes_per_line+j] ); 59 fprintf( stderr, "\n" ); 60 } 61 } 62 63 #endif // DBG_UTIL 64 65 // ----------------------------------------------------------------------------- 66 67 #if (OSL_DEBUG_LEVEL > 1) && defined SALGDI2_TESTTRANS 68 #define DBG_TESTTRANS( _def_drawable ) \ 69 { \ 70 XCopyArea( pXDisp, _def_drawable, aDrawable, GetCopyGC(), \ 71 0, 0, \ 72 pPosAry->mnDestWidth, pPosAry->mnDestHeight, \ 73 0, 0 ); \ 74 } 75 #else // (OSL_DEBUG_LEVEL > 1) && defined SALGDI2_TESTTRANS 76 #define DBG_TESTTRANS( _def_drawable ) 77 #endif // (OSL_DEBUG_LEVEL > 1) && defined SALGDI2_TESTTRANS 78 79 // -=-= X11SalGraphics =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= 80 // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= 81 void X11SalGraphics::CopyScreenArea( Display* pDisplay, 82 Drawable aSrc, int nScreenSrc, int nSrcDepth, 83 Drawable aDest, int nScreenDest, int nDestDepth, 84 GC aDestGC, 85 int src_x, int src_y, 86 unsigned int w, unsigned int h, 87 int dest_x, int dest_y ) 88 { 89 if( nSrcDepth == nDestDepth ) 90 { 91 if( nScreenSrc == nScreenDest ) 92 XCopyArea( pDisplay, aSrc, aDest, aDestGC, 93 src_x, src_y, w, h, dest_x, dest_y ); 94 else 95 { 96 SalXLib* pLib = GetX11SalData()->GetDisplay()->GetXLib(); 97 pLib->PushXErrorLevel( true ); 98 XImage* pImage = XGetImage( pDisplay, aSrc, src_x, src_y, w, h, 99 AllPlanes, ZPixmap ); 100 if( pImage ) 101 { 102 if( pImage->data ) 103 { 104 XPutImage( pDisplay, aDest, aDestGC, pImage, 105 0, 0, dest_x, dest_y, w, h ); 106 } 107 XDestroyImage( pImage ); 108 } 109 pLib->PopXErrorLevel(); 110 } 111 } 112 else 113 { 114 X11SalBitmap aBM; 115 aBM.ImplCreateFromDrawable( aSrc, nScreenSrc, nSrcDepth, src_x, src_y, w, h ); 116 SalTwoRect aTwoRect; 117 aTwoRect.mnSrcX = aTwoRect.mnSrcY = 0; 118 aTwoRect.mnSrcWidth = aTwoRect.mnDestWidth = w; 119 aTwoRect.mnSrcHeight = aTwoRect.mnDestHeight = h; 120 aTwoRect.mnDestX = dest_x; 121 aTwoRect.mnDestY = dest_y; 122 aBM.ImplDraw( aDest, nScreenDest, nDestDepth, aTwoRect,aDestGC ); 123 } 124 } 125 126 GC X11SalGraphics::CreateGC( Drawable hDrawable, unsigned long nMask ) 127 { 128 XGCValues values; 129 130 values.graphics_exposures = False; 131 values.foreground = m_pColormap->GetBlackPixel() 132 ^ m_pColormap->GetWhitePixel(); 133 values.function = GXxor; 134 values.line_width = 1; 135 values.fill_style = FillStippled; 136 values.stipple = GetDisplay()->GetInvert50( m_nScreen ); 137 values.subwindow_mode = ClipByChildren; 138 139 return XCreateGC( GetXDisplay(), hDrawable, nMask | GCSubwindowMode, &values ); 140 } 141 142 // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= 143 inline GC X11SalGraphics::GetMonoGC( Pixmap hPixmap ) 144 { 145 if( !pMonoGC_ ) 146 pMonoGC_ = CreateGC( hPixmap ); 147 148 if( !bMonoGC_ ) 149 { 150 SetClipRegion( pMonoGC_ ); 151 bMonoGC_ = sal_True; 152 } 153 154 return pMonoGC_; 155 } 156 157 // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= 158 inline GC X11SalGraphics::GetCopyGC() 159 { 160 if( bXORMode_ ) return GetInvertGC(); 161 162 if( !pCopyGC_ ) 163 pCopyGC_ = CreateGC( GetDrawable() ); 164 165 if( !bCopyGC_ ) 166 { 167 SetClipRegion( pCopyGC_ ); 168 bCopyGC_ = sal_True; 169 } 170 return pCopyGC_; 171 } 172 173 // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= 174 GC X11SalGraphics::GetInvertGC() 175 { 176 if( !pInvertGC_ ) 177 pInvertGC_ = CreateGC( GetDrawable(), 178 GCGraphicsExposures 179 | GCForeground 180 | GCFunction 181 | GCLineWidth ); 182 183 if( !bInvertGC_ ) 184 { 185 SetClipRegion( pInvertGC_ ); 186 bInvertGC_ = sal_True; 187 } 188 return pInvertGC_; 189 } 190 191 // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= 192 GC X11SalGraphics::GetInvert50GC() 193 { 194 if( !pInvert50GC_ ) 195 { 196 XGCValues values; 197 198 values.graphics_exposures = False; 199 values.foreground = m_pColormap->GetWhitePixel(); 200 values.background = m_pColormap->GetBlackPixel(); 201 values.function = GXinvert; 202 values.line_width = 1; 203 values.line_style = LineSolid; 204 unsigned long nValueMask = 205 GCGraphicsExposures 206 | GCForeground 207 | GCBackground 208 | GCFunction 209 | GCLineWidth 210 | GCLineStyle 211 | GCFillStyle 212 | GCStipple; 213 214 char* pEnv = getenv( "SAL_DO_NOT_USE_INVERT50" ); 215 if( pEnv && ! strcasecmp( pEnv, "true" ) ) 216 { 217 values.fill_style = FillSolid; 218 nValueMask &= ~ GCStipple; 219 } 220 else 221 { 222 values.fill_style = FillStippled; 223 values.stipple = GetDisplay()->GetInvert50( m_nScreen ); 224 } 225 226 pInvert50GC_ = XCreateGC( GetXDisplay(), GetDrawable(), 227 nValueMask, 228 &values ); 229 } 230 231 if( !bInvert50GC_ ) 232 { 233 SetClipRegion( pInvert50GC_ ); 234 bInvert50GC_ = sal_True; 235 } 236 return pInvert50GC_; 237 } 238 239 // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= 240 inline GC X11SalGraphics::GetStippleGC() 241 { 242 if( !pStippleGC_ ) 243 pStippleGC_ = CreateGC( GetDrawable(), 244 GCGraphicsExposures 245 | GCFillStyle 246 | GCLineWidth ); 247 248 if( !bStippleGC_ ) 249 { 250 XSetFunction( GetXDisplay(), pStippleGC_, bXORMode_ ? GXxor : GXcopy ); 251 SetClipRegion( pStippleGC_ ); 252 bStippleGC_ = sal_True; 253 } 254 255 return pStippleGC_; 256 } 257 258 // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= 259 int X11SalGraphics::Clip( XLIB_Region pRegion, 260 int &nX, 261 int &nY, 262 unsigned int &nDX, 263 unsigned int &nDY, 264 int &nSrcX, 265 int &nSrcY ) const 266 { 267 XRectangle aRect; 268 XClipBox( pRegion, &aRect ); 269 270 if( int(nX + nDX) <= int(aRect.x) || nX >= int(aRect.x + aRect.width) ) 271 return RectangleOut; 272 if( int(nY + nDY) <= int(aRect.y) || nY >= int(aRect.y + aRect.height) ) 273 return RectangleOut; 274 275 if( nX < aRect.x ) 276 { 277 nSrcX += aRect.x - nX; 278 nDX -= aRect.x - nX; 279 nX = aRect.x; 280 } 281 else if( int(nX + nDX) > int(aRect.x + aRect.width) ) 282 nDX = aRect.x + aRect.width - nX; 283 284 if( nY < aRect.y ) 285 { 286 nSrcY += aRect.y - nY; 287 nDY -= aRect.y - nY; 288 nY = aRect.y; 289 } 290 else if( int(nY + nDY) > int(aRect.y + aRect.height) ) 291 nDY = aRect.y + aRect.height - nY; 292 293 return RectangleIn; 294 } 295 296 // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= 297 int X11SalGraphics::Clip( int &nX, 298 int &nY, 299 unsigned int &nDX, 300 unsigned int &nDY, 301 int &nSrcX, 302 int &nSrcY ) const 303 304 { 305 if( pPaintRegion_ 306 && RectangleOut == Clip( pPaintRegion_, nX, nY, nDX, nDY, nSrcX, nSrcY ) ) 307 return RectangleOut; 308 309 if( mpClipRegion 310 && RectangleOut == Clip( mpClipRegion, nX, nY, nDX, nDY, nSrcX, nSrcY ) ) 311 return RectangleOut; 312 313 int nPaint; 314 if( pPaintRegion_ ) 315 { 316 nPaint = XRectInRegion( pPaintRegion_, nX, nY, nDX, nDY ); 317 if( RectangleOut == nPaint ) 318 return RectangleOut; 319 } 320 else 321 nPaint = RectangleIn; 322 323 int nClip; 324 if( mpClipRegion ) 325 { 326 nClip = XRectInRegion( mpClipRegion, nX, nY, nDX, nDY ); 327 if( RectangleOut == nClip ) 328 return RectangleOut; 329 } 330 else 331 nClip = RectangleIn; 332 333 return RectangleIn == nClip && RectangleIn == nPaint 334 ? RectangleIn 335 : RectanglePart; 336 } 337 338 // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= 339 GC X11SalGraphics::SetMask( int &nX, 340 int &nY, 341 unsigned int &nDX, 342 unsigned int &nDY, 343 int &nSrcX, 344 int &nSrcY, 345 Pixmap hClipMask ) 346 { 347 int n = Clip( nX, nY, nDX, nDY, nSrcX, nSrcY ); 348 if( RectangleOut == n ) 349 return NULL; 350 351 Display *pDisplay = GetXDisplay(); 352 353 if( !pMaskGC_ ) 354 pMaskGC_ = CreateGC( GetDrawable() ); 355 356 if( RectangleIn == n ) 357 { 358 XSetClipMask( pDisplay, pMaskGC_, hClipMask ); 359 XSetClipOrigin( pDisplay, pMaskGC_, nX - nSrcX, nY - nSrcY ); 360 return pMaskGC_; 361 } 362 363 // - - - - create alternate clip pixmap for region clipping - - - - 364 Pixmap hPixmap = XCreatePixmap( pDisplay, hClipMask, nDX, nDY, 1 ); 365 366 if( !hPixmap ) 367 { 368 #if (OSL_DEBUG_LEVEL > 1) || defined DBG_UTIL 369 fprintf( stderr, "X11SalGraphics::SetMask !hPixmap\n" ); 370 #endif 371 return NULL; 372 } 373 374 // - - - - reset pixmap; all 0 - - - - - - - - - - - - - - - - - - - 375 XFillRectangle( pDisplay, 376 hPixmap, 377 GetDisplay()->GetMonoGC( m_nScreen ), 378 0, 0, 379 nDX, nDY ); 380 381 // - - - - copy pixmap only within region - - - - - - - - - - - - - 382 GC pMonoGC = GetMonoGC( hPixmap ); 383 XSetClipOrigin( pDisplay, pMonoGC, -nX, -nY ); 384 XCopyArea( pDisplay, 385 hClipMask, // Source 386 hPixmap, // Destination 387 pMonoGC, 388 nSrcX, nSrcY, // Source 389 nDX, nDY, // Width & Height 390 0, 0 ); // Destination 391 392 XSetClipMask( pDisplay, pMaskGC_, hPixmap ); 393 XSetClipOrigin( pDisplay, pMaskGC_, nX, nY ); 394 395 XFreePixmap( pDisplay, hPixmap ); 396 return pMaskGC_; 397 } 398 399 // -=-= SalGraphics =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= 400 // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= 401 402 extern "C" 403 { 404 static Bool GraphicsExposePredicate( Display*, XEvent* pEvent, XPointer pFrameWindow ) 405 { 406 Bool bRet = False; 407 if( (pEvent->type == GraphicsExpose || pEvent->type == NoExpose) && 408 pEvent->xnoexpose.drawable == (Drawable)pFrameWindow ) 409 { 410 bRet = True; 411 } 412 return bRet; 413 } 414 } 415 416 417 void X11SalGraphics::YieldGraphicsExpose() 418 { 419 // get frame if necessary 420 SalFrame* pFrame = m_pFrame; 421 Display* pDisplay = GetXDisplay(); 422 XLIB_Window aWindow = GetDrawable(); 423 if( ! pFrame ) 424 { 425 const std::list< SalFrame* >& rFrames = GetX11SalData()->GetDisplay()->getFrames(); 426 for( std::list< SalFrame* >::const_iterator it = rFrames.begin(); it != rFrames.end() && ! pFrame; ++it ) 427 { 428 const SystemEnvData* pEnvData = (*it)->GetSystemData(); 429 if( Drawable(pEnvData->aWindow) == aWindow ) 430 pFrame = *it; 431 } 432 if( ! pFrame ) 433 return; 434 } 435 436 XEvent aEvent; 437 while( XCheckTypedWindowEvent( pDisplay, aWindow, Expose, &aEvent ) ) 438 { 439 SalPaintEvent aPEvt( aEvent.xexpose.x, aEvent.xexpose.y, aEvent.xexpose.width+1, aEvent.xexpose.height+1 ); 440 pFrame->CallCallback( SALEVENT_PAINT, &aPEvt ); 441 } 442 443 do 444 { 445 if( ! GetDisplay()->XIfEventWithTimeout( &aEvent, (XPointer)aWindow, GraphicsExposePredicate ) ) 446 // this should not happen at all; still sometimes it happens 447 break; 448 449 if( aEvent.type == NoExpose ) 450 break; 451 452 if( pFrame ) 453 { 454 SalPaintEvent aPEvt( aEvent.xgraphicsexpose.x, aEvent.xgraphicsexpose.y, aEvent.xgraphicsexpose.width+1, aEvent.xgraphicsexpose.height+1 ); 455 pFrame->CallCallback( SALEVENT_PAINT, &aPEvt ); 456 } 457 } while( aEvent.xgraphicsexpose.count != 0 ); 458 } 459 460 void X11SalGraphics::copyBits( const SalTwoRect *pPosAry, 461 SalGraphics *pSSrcGraphics ) 462 { 463 X11SalGraphics* pSrcGraphics = pSSrcGraphics 464 ? static_cast<X11SalGraphics*>(pSSrcGraphics) 465 : this; 466 467 if( pPosAry->mnSrcWidth <= 0 468 || pPosAry->mnSrcHeight <= 0 469 || pPosAry->mnDestWidth <= 0 470 || pPosAry->mnDestHeight <= 0 ) 471 { 472 return; 473 } 474 475 int n; 476 if( pSrcGraphics == this ) 477 { 478 n = 2; 479 } 480 else if( pSrcGraphics->bWindow_ ) 481 { 482 // window or compatible virtual device 483 if( pSrcGraphics->GetDisplay() == GetDisplay() && 484 pSrcGraphics->m_nScreen == m_nScreen && 485 pSrcGraphics->GetVisual().GetDepth() == GetVisual().GetDepth() 486 ) 487 n = 2; // same Display 488 else 489 n = 1; // printer or other display 490 } 491 else if( pSrcGraphics->bVirDev_ ) 492 { 493 // printer compatible virtual device 494 if( bPrinter_ ) 495 n = 2; // printer or compatible virtual device == same display 496 else 497 n = 1; // window or compatible virtual device 498 } 499 else 500 n = 0; 501 502 if( n == 2 503 && pPosAry->mnSrcWidth == pPosAry->mnDestWidth 504 && pPosAry->mnSrcHeight == pPosAry->mnDestHeight 505 ) 506 { 507 // #i60699# Need to generate graphics exposures (to repaint 508 // obscured areas beneath overlapping windows), src and dest 509 // are the same window. 510 const bool bNeedGraphicsExposures( pSrcGraphics == this && 511 !bVirDev_ && 512 pSrcGraphics->bWindow_ ); 513 514 GC pCopyGC; 515 516 if( bXORMode_ 517 && !pSrcGraphics->bVirDev_ 518 && (GetDisplay()->GetProperties() & PROPERTY_BUG_XCopyArea_GXxor) ) 519 { 520 Pixmap hPixmap = XCreatePixmap( GetXDisplay(), 521 pSrcGraphics->GetDrawable(), // source 522 pPosAry->mnSrcWidth, pPosAry->mnSrcHeight, 523 pSrcGraphics->GetBitCount() ); 524 525 pCopyGC = GetDisplay()->GetCopyGC( m_nScreen ); 526 527 if( bNeedGraphicsExposures ) 528 XSetGraphicsExposures( GetXDisplay(), 529 pCopyGC, 530 True ); 531 532 XCopyArea( GetXDisplay(), 533 pSrcGraphics->GetDrawable(), // source 534 hPixmap, // destination 535 pCopyGC, // no clipping 536 pPosAry->mnSrcX, pPosAry->mnSrcY, 537 pPosAry->mnSrcWidth, pPosAry->mnSrcHeight, 538 0, 0 ); // destination 539 XCopyArea( GetXDisplay(), 540 hPixmap, // source 541 GetDrawable(), // destination 542 GetInvertGC(), // destination clipping 543 0, 0, // source 544 pPosAry->mnSrcWidth, pPosAry->mnSrcHeight, 545 pPosAry->mnDestX, pPosAry->mnDestY ); 546 XFreePixmap( GetXDisplay(), hPixmap ); 547 } 548 else 549 { 550 pCopyGC = GetCopyGC(); 551 552 if( bNeedGraphicsExposures ) 553 XSetGraphicsExposures( GetXDisplay(), 554 pCopyGC, 555 True ); 556 557 XCopyArea( GetXDisplay(), 558 pSrcGraphics->GetDrawable(), // source 559 GetDrawable(), // destination 560 pCopyGC, // destination clipping 561 pPosAry->mnSrcX, pPosAry->mnSrcY, 562 pPosAry->mnSrcWidth, pPosAry->mnSrcHeight, 563 pPosAry->mnDestX, pPosAry->mnDestY ); 564 } 565 566 if( bNeedGraphicsExposures ) 567 { 568 YieldGraphicsExpose(); 569 570 if( pCopyGC ) 571 XSetGraphicsExposures( GetXDisplay(), 572 pCopyGC, 573 False ); 574 } 575 } 576 else if( n ) 577 { 578 // #i60699# No chance to handle graphics exposures - we copy 579 // to a temp bitmap first, into which no repaints are 580 // technically possible. 581 SalBitmap *pDDB = pSrcGraphics->getBitmap( pPosAry->mnSrcX, 582 pPosAry->mnSrcY, 583 pPosAry->mnSrcWidth, 584 pPosAry->mnSrcHeight ); 585 586 if( !pDDB ) 587 { 588 stderr0( "SalGraphics::CopyBits !pSrcGraphics->GetBitmap()\n" ); 589 return; 590 } 591 592 SalTwoRect aPosAry( *pPosAry ); 593 594 aPosAry.mnSrcX = 0, aPosAry.mnSrcY = 0; 595 drawBitmap( &aPosAry, *pDDB ); 596 597 delete pDDB; 598 } 599 else { 600 stderr0( "X11SalGraphics::CopyBits from Printer not yet implemented\n" ); 601 } 602 } 603 604 // -------------------------------------------------------------------------- 605 606 void X11SalGraphics::copyArea ( long nDestX, long nDestY, 607 long nSrcX, long nSrcY, 608 long nSrcWidth, long nSrcHeight, 609 sal_uInt16 ) 610 { 611 SalTwoRect aPosAry; 612 613 aPosAry.mnDestX = nDestX; 614 aPosAry.mnDestY = nDestY; 615 aPosAry.mnDestWidth = nSrcWidth; 616 aPosAry.mnDestHeight = nSrcHeight; 617 618 aPosAry.mnSrcX = nSrcX; 619 aPosAry.mnSrcY = nSrcY; 620 aPosAry.mnSrcWidth = nSrcWidth; 621 aPosAry.mnSrcHeight = nSrcHeight; 622 623 copyBits ( &aPosAry, 0 ); 624 } 625 626 // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= 627 void X11SalGraphics::drawBitmap( const SalTwoRect* pPosAry, const SalBitmap& rSalBitmap ) 628 { 629 const SalDisplay* pSalDisp = GetDisplay(); 630 Display* pXDisp = pSalDisp->GetDisplay(); 631 const Drawable aDrawable( GetDrawable() ); 632 const SalColormap& rColMap = pSalDisp->GetColormap( m_nScreen ); 633 const long nDepth = GetDisplay()->GetVisual( m_nScreen ).GetDepth(); 634 GC aGC( GetCopyGC() ); 635 XGCValues aOldVal, aNewVal; 636 int nValues = GCForeground | GCBackground; 637 638 if( rSalBitmap.GetBitCount() == 1 ) 639 { 640 // set foreground/background values for 1Bit bitmaps 641 XGetGCValues( pXDisp, aGC, nValues, &aOldVal ); 642 aNewVal.foreground = rColMap.GetWhitePixel(), aNewVal.background = rColMap.GetBlackPixel(); 643 XChangeGC( pXDisp, aGC, nValues, &aNewVal ); 644 } 645 646 static_cast<const X11SalBitmap&>(rSalBitmap).ImplDraw( aDrawable, m_nScreen, nDepth, *pPosAry, aGC ); 647 648 if( rSalBitmap.GetBitCount() == 1 ) 649 XChangeGC( pXDisp, aGC, nValues, &aOldVal ); 650 XFlush( pXDisp ); 651 } 652 653 // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= 654 655 void X11SalGraphics::drawBitmap( const SalTwoRect* pPosAry, 656 const SalBitmap& rSrcBitmap, 657 const SalBitmap& rMaskBitmap ) 658 { 659 DBG_ASSERT( !bPrinter_, "Drawing of transparent bitmaps on printer devices is strictly forbidden" ); 660 661 // decide if alpha masking or transparency masking is needed 662 BitmapBuffer* pAlphaBuffer = const_cast<SalBitmap&>(rMaskBitmap).AcquireBuffer( sal_True ); 663 if( pAlphaBuffer != NULL ) 664 { 665 int nMaskFormat = pAlphaBuffer->mnFormat; 666 const_cast<SalBitmap&>(rMaskBitmap).ReleaseBuffer( pAlphaBuffer, sal_True ); 667 if( nMaskFormat == BMP_FORMAT_8BIT_PAL ) 668 drawAlphaBitmap( *pPosAry, rSrcBitmap, rMaskBitmap ); 669 } 670 671 drawMaskedBitmap( pPosAry, rSrcBitmap, rMaskBitmap ); 672 } 673 674 // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= 675 676 void X11SalGraphics::drawMaskedBitmap( const SalTwoRect* pPosAry, 677 const SalBitmap& rSalBitmap, 678 const SalBitmap& rTransBitmap ) 679 { 680 const SalDisplay* pSalDisp = GetDisplay(); 681 Display* pXDisp = pSalDisp->GetDisplay(); 682 Drawable aDrawable( GetDrawable() ); 683 684 // figure work mode depth. If this is a VDev Drawable, use its 685 // bitdepth to create pixmaps for, otherwise, XCopyArea will 686 // refuse to work. 687 const sal_uInt16 nDepth( m_pVDev ? 688 m_pVDev->GetDepth() : 689 pSalDisp->GetVisual( m_nScreen ).GetDepth() ); 690 Pixmap aFG( XCreatePixmap( pXDisp, aDrawable, pPosAry->mnDestWidth, 691 pPosAry->mnDestHeight, nDepth ) ); 692 Pixmap aBG( XCreatePixmap( pXDisp, aDrawable, pPosAry->mnDestWidth, 693 pPosAry->mnDestHeight, nDepth ) ); 694 695 if( aFG && aBG ) 696 { 697 GC aTmpGC; 698 XGCValues aValues; 699 const SalColormap& rColMap = pSalDisp->GetColormap( m_nScreen ); 700 const int nBlack = rColMap.GetBlackPixel(), nWhite = rColMap.GetWhitePixel(); 701 const int nValues = GCFunction | GCForeground | GCBackground; 702 SalTwoRect aTmpRect( *pPosAry ); aTmpRect.mnDestX = aTmpRect.mnDestY = 0; 703 704 // draw paint bitmap in pixmap #1 705 aValues.function = GXcopy, aValues.foreground = nWhite, aValues.background = nBlack; 706 aTmpGC = XCreateGC( pXDisp, aFG, nValues, &aValues ); 707 static_cast<const X11SalBitmap&>(rSalBitmap).ImplDraw( aFG, m_nScreen, nDepth, aTmpRect, aTmpGC ); 708 DBG_TESTTRANS( aFG ); 709 710 // draw background in pixmap #2 711 XCopyArea( pXDisp, aDrawable, aBG, aTmpGC, 712 pPosAry->mnDestX, pPosAry->mnDestY, 713 pPosAry->mnDestWidth, pPosAry->mnDestHeight, 714 0, 0 ); 715 716 DBG_TESTTRANS( aBG ); 717 718 // mask out paint bitmap in pixmap #1 (transparent areas 0) 719 aValues.function = GXand, aValues.foreground = 0x00000000, aValues.background = 0xffffffff; 720 XChangeGC( pXDisp, aTmpGC, nValues, &aValues ); 721 static_cast<const X11SalBitmap&>(rTransBitmap).ImplDraw( aFG, m_nScreen, 1, aTmpRect, aTmpGC ); 722 723 DBG_TESTTRANS( aFG ); 724 725 // #105055# For XOR mode, keep background behind bitmap intact 726 if( !bXORMode_ ) 727 { 728 // mask out background in pixmap #2 (nontransparent areas 0) 729 aValues.function = GXand, aValues.foreground = 0xffffffff, aValues.background = 0x00000000; 730 XChangeGC( pXDisp, aTmpGC, nValues, &aValues ); 731 static_cast<const X11SalBitmap&>(rTransBitmap).ImplDraw( aBG, m_nScreen, 1, aTmpRect, aTmpGC ); 732 733 DBG_TESTTRANS( aBG ); 734 } 735 736 // merge pixmap #1 and pixmap #2 in pixmap #2 737 aValues.function = GXxor, aValues.foreground = 0xffffffff, aValues.background = 0x00000000; 738 XChangeGC( pXDisp, aTmpGC, nValues, &aValues ); 739 XCopyArea( pXDisp, aFG, aBG, aTmpGC, 740 0, 0, 741 pPosAry->mnDestWidth, pPosAry->mnDestHeight, 742 0, 0 ); 743 DBG_TESTTRANS( aBG ); 744 745 // #105055# Disable XOR temporarily 746 sal_Bool bOldXORMode( bXORMode_ ); 747 bXORMode_ = sal_False; 748 749 // copy pixmap #2 (result) to background 750 XCopyArea( pXDisp, aBG, aDrawable, GetCopyGC(), 751 0, 0, 752 pPosAry->mnDestWidth, pPosAry->mnDestHeight, 753 pPosAry->mnDestX, pPosAry->mnDestY ); 754 755 DBG_TESTTRANS( aBG ); 756 757 bXORMode_ = bOldXORMode; 758 759 XFreeGC( pXDisp, aTmpGC ); 760 XFlush( pXDisp ); 761 } 762 else 763 drawBitmap( pPosAry, rSalBitmap ); 764 765 if( aFG ) 766 XFreePixmap( pXDisp, aFG ); 767 768 if( aBG ) 769 XFreePixmap( pXDisp, aBG ); 770 } 771 772 // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= 773 bool X11SalGraphics::drawAlphaBitmap( const SalTwoRect& rTR, 774 const SalBitmap& rSrcBitmap, const SalBitmap& rAlphaBmp ) 775 { 776 // non 8-bit alpha not implemented yet 777 if( rAlphaBmp.GetBitCount() != 8 ) 778 return false; 779 780 // horizontal mirroring not implemented yet 781 if( rTR.mnDestWidth < 0 ) 782 return false; 783 784 // stretched conversion is not implemented yet 785 if( rTR.mnDestWidth != rTR.mnSrcWidth ) 786 return false; 787 if( rTR.mnDestHeight!= rTR.mnSrcHeight ) 788 return false; 789 790 XRenderPeer& rPeer = XRenderPeer::GetInstance(); 791 if( rPeer.GetVersion() < 0x02 ) 792 return false; 793 794 // create destination picture 795 Picture aDstPic = GetXRenderPicture(); 796 if( !aDstPic ) 797 return false; 798 799 const SalDisplay* pSalDisp = GetDisplay(); 800 const SalVisual& rSalVis = pSalDisp->GetVisual( m_nScreen ); 801 Display* pXDisplay = pSalDisp->GetDisplay(); 802 803 // create source Picture 804 int nDepth = m_pVDev ? m_pVDev->GetDepth() : rSalVis.GetDepth(); 805 const X11SalBitmap& rSrcX11Bmp = static_cast<const X11SalBitmap&>( rSrcBitmap ); 806 ImplSalDDB* pSrcDDB = rSrcX11Bmp.ImplGetDDB( hDrawable_, m_nScreen, nDepth, rTR ); 807 if( !pSrcDDB ) 808 return false; 809 810 //#i75249# workaround for ImplGetDDB() giving us back a different depth than 811 // we requested. E.g. mask pixmaps are always compatible with the drawable 812 // TODO: find an appropriate picture format for these cases 813 // then remove the workaround below and the one for #i75531# 814 if( nDepth != pSrcDDB->ImplGetDepth() ) 815 return false; 816 817 Pixmap aSrcPM = pSrcDDB->ImplGetPixmap(); 818 if( !aSrcPM ) 819 return false; 820 821 // create source picture 822 // TODO: use scoped picture 823 Visual* pSrcXVisual = rSalVis.GetVisual(); 824 XRenderPictFormat* pSrcVisFmt = rPeer.FindVisualFormat( pSrcXVisual ); 825 if( !pSrcVisFmt ) 826 return false; 827 Picture aSrcPic = rPeer.CreatePicture( aSrcPM, pSrcVisFmt, 0, NULL ); 828 if( !aSrcPic ) 829 return false; 830 831 // create alpha Picture 832 833 // TODO: use SalX11Bitmap functionality and caching for the Alpha Pixmap 834 // problem is that they don't provide an 8bit Pixmap on a non-8bit display 835 BitmapBuffer* pAlphaBuffer = const_cast<SalBitmap&>(rAlphaBmp).AcquireBuffer( sal_True ); 836 837 // an XImage needs its data top_down 838 // TODO: avoid wrongly oriented images in upper layers! 839 const int nImageSize = pAlphaBuffer->mnHeight * pAlphaBuffer->mnScanlineSize; 840 const char* pSrcBits = (char*)pAlphaBuffer->mpBits; 841 char* pAlphaBits = new char[ nImageSize ]; 842 if( BMP_SCANLINE_ADJUSTMENT( pAlphaBuffer->mnFormat ) == BMP_FORMAT_TOP_DOWN ) 843 memcpy( pAlphaBits, pSrcBits, nImageSize ); 844 else 845 { 846 char* pDstBits = pAlphaBits + nImageSize; 847 const int nLineSize = pAlphaBuffer->mnScanlineSize; 848 for(; (pDstBits -= nLineSize) >= pAlphaBits; pSrcBits += nLineSize ) 849 memcpy( pDstBits, pSrcBits, nLineSize ); 850 } 851 852 // the alpha values need to be inverted for XRender 853 // TODO: make upper layers use standard alpha 854 long* pLDst = (long*)pAlphaBits; 855 for( int i = nImageSize/sizeof(long); --i >= 0; ++pLDst ) 856 *pLDst = ~*pLDst; 857 858 char* pCDst = (char*)pLDst; 859 for( int i = nImageSize & (sizeof(long)-1); --i >= 0; ++pCDst ) 860 *pCDst = ~*pCDst; 861 862 const XRenderPictFormat* pAlphaFormat = rPeer.GetStandardFormatA8(); 863 XImage* pAlphaImg = XCreateImage( pXDisplay, pSrcXVisual, 8, ZPixmap, 0, 864 pAlphaBits, pAlphaBuffer->mnWidth, pAlphaBuffer->mnHeight, 865 pAlphaFormat->depth, pAlphaBuffer->mnScanlineSize ); 866 867 Pixmap aAlphaPM = XCreatePixmap( pXDisplay, hDrawable_, 868 rTR.mnDestWidth, rTR.mnDestHeight, 8 ); 869 870 XGCValues aAlphaGCV; 871 aAlphaGCV.function = GXcopy; 872 GC aAlphaGC = XCreateGC( pXDisplay, aAlphaPM, GCFunction, &aAlphaGCV ); 873 XPutImage( pXDisplay, aAlphaPM, aAlphaGC, pAlphaImg, 874 rTR.mnSrcX, rTR.mnSrcY, 0, 0, rTR.mnDestWidth, rTR.mnDestHeight ); 875 XFreeGC( pXDisplay, aAlphaGC ); 876 XFree( pAlphaImg ); 877 if( pAlphaBits != (char*)pAlphaBuffer->mpBits ) 878 delete[] pAlphaBits; 879 880 const_cast<SalBitmap&>(rAlphaBmp).ReleaseBuffer( pAlphaBuffer, sal_True ); 881 882 XRenderPictureAttributes aAttr; 883 aAttr.repeat = true; 884 Picture aAlphaPic = rPeer.CreatePicture( aAlphaPM, pAlphaFormat, CPRepeat, &aAttr ); 885 if( !aAlphaPic ) 886 return false; 887 888 // set clipping 889 if( mpClipRegion && !XEmptyRegion( mpClipRegion ) ) 890 rPeer.SetPictureClipRegion( aDstPic, mpClipRegion ); 891 892 // paint source * mask over destination picture 893 rPeer.CompositePicture( PictOpOver, aSrcPic, aAlphaPic, aDstPic, 894 rTR.mnSrcX, rTR.mnSrcY, 0, 0, 895 rTR.mnDestX, rTR.mnDestY, rTR.mnDestWidth, rTR.mnDestHeight ); 896 897 // TODO: used ScopedPic 898 rPeer.FreePicture( aAlphaPic ); 899 XFreePixmap(pXDisplay, aAlphaPM); 900 rPeer.FreePicture( aSrcPic ); 901 return true; 902 } 903 904 // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= 905 bool X11SalGraphics::drawAlphaRect( long nX, long nY, long nWidth, 906 long nHeight, sal_uInt8 nTransparency ) 907 { 908 if( ! m_pFrame && ! m_pVDev ) 909 return false; 910 911 if( bPenGC_ || !bBrushGC_ || bXORMode_ ) 912 return false; // can only perform solid fills without XOR. 913 914 if( m_pVDev && m_pVDev->GetDepth() < 8 ) 915 return false; 916 917 XRenderPeer& rPeer = XRenderPeer::GetInstance(); 918 if( rPeer.GetVersion() < 0x02 ) // TODO: replace with better test 919 return false; 920 921 Picture aDstPic = GetXRenderPicture(); 922 if( !aDstPic ) 923 return false; 924 925 const double fTransparency = (100 - nTransparency) * (1.0/100); 926 const XRenderColor aRenderColor = GetXRenderColor( nBrushColor_ , fTransparency); 927 928 rPeer.FillRectangle( PictOpOver, 929 aDstPic, 930 &aRenderColor, 931 nX, nY, 932 nWidth, nHeight ); 933 934 return true; 935 } 936 937 // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= 938 void X11SalGraphics::drawBitmap( const SalTwoRect*, 939 const SalBitmap&, 940 SalColor ) 941 { 942 DBG_ERROR( "::DrawBitmap with transparent color not supported" ); 943 } 944 945 // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= 946 void X11SalGraphics::drawMask( const SalTwoRect* pPosAry, 947 const SalBitmap &rSalBitmap, 948 SalColor nMaskColor ) 949 { 950 const SalDisplay* pSalDisp = GetDisplay(); 951 Display* pXDisp = pSalDisp->GetDisplay(); 952 Drawable aDrawable( GetDrawable() ); 953 Pixmap aStipple( XCreatePixmap( pXDisp, aDrawable, 954 pPosAry->mnDestWidth, 955 pPosAry->mnDestHeight, 1 ) ); 956 957 if( aStipple ) 958 { 959 SalTwoRect aTwoRect( *pPosAry ); aTwoRect.mnDestX = aTwoRect.mnDestY = 0; 960 GC aTmpGC; 961 XGCValues aValues; 962 963 // create a stipple bitmap first (set bits are changed to unset bits and vice versa) 964 aValues.function = GXcopyInverted; 965 aValues.foreground = 1, aValues.background = 0; 966 aTmpGC = XCreateGC( pXDisp, aStipple, GCFunction | GCForeground | GCBackground, &aValues ); 967 static_cast<const X11SalBitmap&>(rSalBitmap).ImplDraw( aStipple, m_nScreen, 1, aTwoRect, aTmpGC ); 968 969 XFreeGC( pXDisp, aTmpGC ); 970 971 // Set stipple and draw rectangle 972 GC aStippleGC( GetStippleGC() ); 973 int nX = pPosAry->mnDestX, nY = pPosAry->mnDestY; 974 975 XSetStipple( pXDisp, aStippleGC, aStipple ); 976 XSetTSOrigin( pXDisp, aStippleGC, nX, nY ); 977 XSetForeground( pXDisp, aStippleGC, GetPixel( nMaskColor ) ); 978 XFillRectangle( pXDisp, aDrawable, aStippleGC, 979 nX, nY, 980 pPosAry->mnDestWidth, pPosAry->mnDestHeight ); 981 XFreePixmap( pXDisp, aStipple ); 982 XFlush( pXDisp ); 983 } 984 else 985 drawBitmap( pPosAry, rSalBitmap ); 986 } 987 988 // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= 989 SalBitmap *X11SalGraphics::getBitmap( long nX, long nY, long nDX, long nDY ) 990 { 991 if( bPrinter_ && !bVirDev_ ) 992 return NULL; 993 994 bool bFakeWindowBG = false; 995 996 // normalize 997 if( nDX < 0 ) 998 { 999 nX += nDX; 1000 nDX = -nDX; 1001 } 1002 if ( nDY < 0 ) 1003 { 1004 nY += nDY; 1005 nDY = -nDY; 1006 } 1007 1008 if( bWindow_ && !bVirDev_ ) 1009 { 1010 XWindowAttributes aAttrib; 1011 1012 XGetWindowAttributes( GetXDisplay(), GetDrawable(), &aAttrib ); 1013 if( aAttrib.map_state != IsViewable ) 1014 bFakeWindowBG = true; 1015 else 1016 { 1017 long nOrgDX = nDX, nOrgDY = nDY; 1018 1019 // clip to window size 1020 if ( nX < 0 ) 1021 { 1022 nDX += nX; 1023 nX = 0; 1024 } 1025 if ( nY < 0 ) 1026 { 1027 nDY += nY; 1028 nY = 0; 1029 } 1030 if( nX + nDX > aAttrib.width ) 1031 nDX = aAttrib.width - nX; 1032 if( nY + nDY > aAttrib.height ) 1033 nDY = aAttrib.height - nY; 1034 1035 // inside ? 1036 if( nDX <= 0 || nDY <= 0 ) 1037 { 1038 bFakeWindowBG = true; 1039 nDX = nOrgDX; 1040 nDY = nOrgDY; 1041 } 1042 } 1043 } 1044 1045 X11SalBitmap* pSalBitmap = new X11SalBitmap; 1046 sal_uInt16 nBitCount = GetBitCount(); 1047 1048 if( &GetDisplay()->GetColormap( m_nScreen ) != &GetColormap() ) 1049 nBitCount = 1; 1050 1051 if( ! bFakeWindowBG ) 1052 pSalBitmap->ImplCreateFromDrawable( GetDrawable(), m_nScreen, nBitCount, nX, nY, nDX, nDY ); 1053 else 1054 pSalBitmap->Create( Size( nDX, nDY ), (nBitCount > 8) ? 24 : nBitCount, BitmapPalette( nBitCount > 8 ? nBitCount : 0 ) ); 1055 1056 return pSalBitmap; 1057 } 1058 1059 // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= 1060 SalColor X11SalGraphics::getPixel( long nX, long nY ) 1061 { 1062 if( bWindow_ && !bVirDev_ ) 1063 { 1064 XWindowAttributes aAttrib; 1065 1066 XGetWindowAttributes( GetXDisplay(), GetDrawable(), &aAttrib ); 1067 if( aAttrib.map_state != IsViewable ) 1068 { 1069 stderr0( "X11SalGraphics::GetPixel drawable not viewable\n" ); 1070 return 0; 1071 } 1072 } 1073 1074 XImage *pXImage = XGetImage( GetXDisplay(), 1075 GetDrawable(), 1076 nX, nY, 1077 1, 1, 1078 AllPlanes, 1079 ZPixmap ); 1080 if( !pXImage ) 1081 { 1082 stderr0( "X11SalGraphics::GetPixel !XGetImage()\n" ); 1083 return 0; 1084 } 1085 1086 XColor aXColor; 1087 1088 aXColor.pixel = XGetPixel( pXImage, 0, 0 ); 1089 XDestroyImage( pXImage ); 1090 1091 return GetColormap().GetColor( aXColor.pixel ); 1092 } 1093 1094 // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= 1095 void X11SalGraphics::invert( long nX, 1096 long nY, 1097 long nDX, 1098 long nDY, 1099 SalInvert nFlags ) 1100 { 1101 GC pGC; 1102 if( SAL_INVERT_50 & nFlags ) 1103 { 1104 pGC = GetInvert50GC(); 1105 XFillRectangle( GetXDisplay(), GetDrawable(), pGC, nX, nY, nDX, nDY ); 1106 } 1107 else 1108 { 1109 if ( SAL_INVERT_TRACKFRAME & nFlags ) 1110 { 1111 pGC = GetTrackingGC(); 1112 XDrawRectangle( GetXDisplay(), GetDrawable(), pGC, nX, nY, nDX, nDY ); 1113 } 1114 else 1115 { 1116 pGC = GetInvertGC(); 1117 XFillRectangle( GetXDisplay(), GetDrawable(), pGC, nX, nY, nDX, nDY ); 1118 } 1119 } 1120 } 1121 1122 bool X11SalGraphics::supportsOperation( OutDevSupportType eType ) const 1123 { 1124 bool bRet = false; 1125 switch( eType ) 1126 { 1127 case OutDevSupport_TransparentRect: 1128 case OutDevSupport_B2DDraw: 1129 { 1130 XRenderPeer& rPeer = XRenderPeer::GetInstance(); 1131 if( rPeer.GetVersion() >= 0x02 ) 1132 { 1133 const SalDisplay* pSalDisp = GetDisplay(); 1134 const SalVisual& rSalVis = pSalDisp->GetVisual( m_nScreen ); 1135 1136 Visual* pDstXVisual = rSalVis.GetVisual(); 1137 XRenderPictFormat* pDstVisFmt = rPeer.FindVisualFormat( pDstXVisual ); 1138 if( pDstVisFmt ) 1139 bRet = true; 1140 } 1141 } 1142 break; 1143 default: break; 1144 } 1145 return bRet; 1146 } 1147 1148