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_svtools.hxx"
26
27 #include <vos/macros.hxx>
28 #include <vcl/bmpacc.hxx>
29 #include <tools/poly.hxx>
30 #include <vcl/outdev.hxx>
31 #include <vcl/window.hxx>
32 #include <vcl/gdimtf.hxx>
33 #include <vcl/metaact.hxx>
34 #include <vcl/metric.hxx>
35 #include <vcl/animate.hxx>
36 #include <vcl/alpha.hxx>
37 #include <vcl/virdev.hxx>
38 #include "grfcache.hxx"
39 #include <svtools/grfmgr.hxx>
40
41 // -----------
42 // - defines -
43 // -----------
44
45 #define MAX_PRINTER_EXT 1024
46 #define MAP( cVal0, cVal1, nFrac ) ((sal_uInt8)((((long)(cVal0)<<20L)+nFrac*((long)(cVal1)-(cVal0)))>>20L))
47 #define WATERMARK_LUM_OFFSET 50
48 #define WATERMARK_CON_OFFSET -70
49
50 // -----------
51 // - helpers -
52 // -----------
53
54 namespace {
55
muckWithBitmap(const Point & rDestPoint,const Size & rDestSize,const Size & rRefSize,bool & o_rbNonBitmapActionEncountered)56 void muckWithBitmap( const Point& rDestPoint,
57 const Size& rDestSize,
58 const Size& rRefSize,
59 bool& o_rbNonBitmapActionEncountered )
60 {
61 const Point aEmptyPoint;
62
63 if( aEmptyPoint != rDestPoint ||
64 rDestSize != rRefSize )
65 {
66 // non-fullscale, or offsetted bmp -> fallback to mtf
67 // rendering
68 o_rbNonBitmapActionEncountered = true;
69 }
70 }
71
muckWithBitmap(const BitmapEx & rBmpEx,const Point & rSrcPoint,const Size & rSrcSize,const Point & rDestPoint,const Size & rDestSize,const Size & rRefSize,bool & o_rbNonBitmapActionEncountered)72 BitmapEx muckWithBitmap( const BitmapEx& rBmpEx,
73 const Point& rSrcPoint,
74 const Size& rSrcSize,
75 const Point& rDestPoint,
76 const Size& rDestSize,
77 const Size& rRefSize,
78 bool& o_rbNonBitmapActionEncountered )
79 {
80 BitmapEx aBmpEx;
81
82 muckWithBitmap(rDestPoint,
83 rDestSize,
84 rRefSize,
85 o_rbNonBitmapActionEncountered);
86
87 if( o_rbNonBitmapActionEncountered )
88 return aBmpEx;
89
90 aBmpEx = rBmpEx;
91
92 if( (rSrcPoint.X() != 0 && rSrcPoint.Y() != 0) ||
93 rSrcSize != rBmpEx.GetSizePixel() )
94 {
95 // crop bitmap to given source rectangle (no
96 // need to copy and convert the whole bitmap)
97 const Rectangle aCropRect( rSrcPoint,
98 rSrcSize );
99 aBmpEx.Crop( aCropRect );
100 }
101
102 return aBmpEx;
103 }
104
105 } // namespace {
106
107
108 // ------------------
109 // - GraphicManager -
110 // ------------------
111
GraphicManager(sal_uLong nCacheSize,sal_uLong nMaxObjCacheSize)112 GraphicManager::GraphicManager( sal_uLong nCacheSize, sal_uLong nMaxObjCacheSize ) :
113 mpCache( new GraphicCache( *this, nCacheSize, nMaxObjCacheSize ) )
114 {
115 }
116
117 // -----------------------------------------------------------------------------
118
~GraphicManager()119 GraphicManager::~GraphicManager()
120 {
121 for( void* pObj = maObjList.First(); pObj; pObj = maObjList.Next() )
122 ( (GraphicObject*) pObj )->GraphicManagerDestroyed();
123
124 delete mpCache;
125 }
126
127 // -----------------------------------------------------------------------------
128
SetMaxCacheSize(sal_uLong nNewCacheSize)129 void GraphicManager::SetMaxCacheSize( sal_uLong nNewCacheSize )
130 {
131 mpCache->SetMaxDisplayCacheSize( nNewCacheSize );
132 }
133
134 // -----------------------------------------------------------------------------
135
GetMaxCacheSize() const136 sal_uLong GraphicManager::GetMaxCacheSize() const
137 {
138 return mpCache->GetMaxDisplayCacheSize();
139 }
140
141 // -----------------------------------------------------------------------------
142
SetMaxObjCacheSize(sal_uLong nNewMaxObjSize,sal_Bool bDestroyGreaterCached)143 void GraphicManager::SetMaxObjCacheSize( sal_uLong nNewMaxObjSize, sal_Bool bDestroyGreaterCached )
144 {
145 mpCache->SetMaxObjDisplayCacheSize( nNewMaxObjSize, bDestroyGreaterCached );
146 }
147
148 // -----------------------------------------------------------------------------
149
GetMaxObjCacheSize() const150 sal_uLong GraphicManager::GetMaxObjCacheSize() const
151 {
152 return mpCache->GetMaxObjDisplayCacheSize();
153 }
154
155 // -----------------------------------------------------------------------------
156
GetUsedCacheSize() const157 sal_uLong GraphicManager::GetUsedCacheSize() const
158 {
159 return mpCache->GetUsedDisplayCacheSize();
160 }
161
162 // -----------------------------------------------------------------------------
163
GetFreeCacheSize() const164 sal_uLong GraphicManager::GetFreeCacheSize() const
165 {
166 return mpCache->GetFreeDisplayCacheSize();
167 }
168
169 // -----------------------------------------------------------------------------
170
SetCacheTimeout(sal_uLong nTimeoutSeconds)171 void GraphicManager::SetCacheTimeout( sal_uLong nTimeoutSeconds )
172 {
173 mpCache->SetCacheTimeout( nTimeoutSeconds );
174 }
175
176 // -----------------------------------------------------------------------------
177
GetCacheTimeout() const178 sal_uLong GraphicManager::GetCacheTimeout() const
179 {
180 return mpCache->GetCacheTimeout();
181 }
182
183 // -----------------------------------------------------------------------------
184
ClearCache()185 void GraphicManager::ClearCache()
186 {
187 mpCache->ClearDisplayCache();
188 }
189
190 // -----------------------------------------------------------------------------
191
ReleaseFromCache(const GraphicObject &)192 void GraphicManager::ReleaseFromCache( const GraphicObject& /*rObj*/ )
193 {
194 // !!!
195 }
196
197 // -----------------------------------------------------------------------------
198
IsInCache(OutputDevice * pOut,const Point & rPt,const Size & rSz,const GraphicObject & rObj,const GraphicAttr & rAttr) const199 sal_Bool GraphicManager::IsInCache( OutputDevice* pOut, const Point& rPt,
200 const Size& rSz, const GraphicObject& rObj,
201 const GraphicAttr& rAttr ) const
202 {
203 return mpCache->IsInDisplayCache( pOut, rPt, rSz, rObj, rAttr );
204 }
205
206 // -----------------------------------------------------------------------------
207
DrawObj(OutputDevice * pOut,const Point & rPt,const Size & rSz,GraphicObject & rObj,const GraphicAttr & rAttr,const sal_uLong nFlags,sal_Bool & rCached)208 sal_Bool GraphicManager::DrawObj( OutputDevice* pOut, const Point& rPt, const Size& rSz,
209 GraphicObject& rObj, const GraphicAttr& rAttr,
210 const sal_uLong nFlags, sal_Bool& rCached )
211 {
212 Point aPt( rPt );
213 Size aSz( rSz );
214 sal_Bool bRet = sal_False;
215
216 rCached = sal_False;
217
218 if( ( rObj.GetType() == GRAPHIC_BITMAP ) || ( rObj.GetType() == GRAPHIC_GDIMETAFILE ) )
219 {
220 // create output and fill cache
221 const Size aOutSize( pOut->GetOutputSizePixel() );
222
223 if( rObj.IsAnimated() || ( pOut->GetOutDevType() == OUTDEV_PRINTER ) ||
224 ( !( nFlags & GRFMGR_DRAW_NO_SUBSTITUTE ) &&
225 ( ( nFlags & GRFMGR_DRAW_SUBSTITUTE ) ||
226 !( nFlags & GRFMGR_DRAW_CACHED ) ||
227 ( pOut->GetConnectMetaFile() && !pOut->IsOutputEnabled() ) ) ) )
228 {
229 // simple output of transformed graphic
230 const Graphic aGraphic( rObj.GetTransformedGraphic( &rAttr ) );
231
232 if( aGraphic.IsSupportedGraphic() )
233 {
234 const sal_uInt16 nRot10 = rAttr.GetRotation() % 3600;
235
236 if( nRot10 )
237 {
238 Polygon aPoly( Rectangle( aPt, aSz ) );
239
240 aPoly.Rotate( aPt, nRot10 );
241 const Rectangle aRotBoundRect( aPoly.GetBoundRect() );
242 aPt = aRotBoundRect.TopLeft();
243 aSz = aRotBoundRect.GetSize();
244 }
245
246 aGraphic.Draw( pOut, aPt, aSz );
247 }
248
249 bRet = sal_True;
250 }
251
252 if( !bRet )
253 {
254 // cached/direct drawing
255 if( !mpCache->DrawDisplayCacheObj( pOut, aPt, aSz, rObj, rAttr ) )
256 bRet = ImplDraw( pOut, aPt, aSz, rObj, rAttr, nFlags, rCached );
257 else
258 bRet = rCached = sal_True;
259 }
260 }
261
262 return bRet;
263 }
264
265 // -----------------------------------------------------------------------------
266
ImplRegisterObj(const GraphicObject & rObj,Graphic & rSubstitute,const ByteString * pID,const GraphicObject * pCopyObj)267 void GraphicManager::ImplRegisterObj( const GraphicObject& rObj, Graphic& rSubstitute,
268 const ByteString* pID, const GraphicObject* pCopyObj )
269 {
270 maObjList.Insert( (void*) &rObj, LIST_APPEND );
271 mpCache->AddGraphicObject( rObj, rSubstitute, pID, pCopyObj );
272 }
273
274 // -----------------------------------------------------------------------------
275
ImplUnregisterObj(const GraphicObject & rObj)276 void GraphicManager::ImplUnregisterObj( const GraphicObject& rObj )
277 {
278 mpCache->ReleaseGraphicObject( rObj );
279 maObjList.Remove( (void*) &rObj );
280 }
281
282 // -----------------------------------------------------------------------------
283
ImplGraphicObjectWasSwappedOut(const GraphicObject & rObj)284 void GraphicManager::ImplGraphicObjectWasSwappedOut( const GraphicObject& rObj )
285 {
286 mpCache->GraphicObjectWasSwappedOut( rObj );
287 }
288
289 // -----------------------------------------------------------------------------
290
ImplGetUniqueID(const GraphicObject & rObj) const291 ByteString GraphicManager::ImplGetUniqueID( const GraphicObject& rObj ) const
292 {
293 return mpCache->GetUniqueID( rObj );
294 }
295
296 // -----------------------------------------------------------------------------
297
298 namespace
299 {
300 struct simpleSortByDataChangeTimeStamp
301 {
operator ()__anone4cae4650211::simpleSortByDataChangeTimeStamp302 bool operator() (GraphicObject* p1, GraphicObject* p2) const
303 {
304 return p1->GetDataChangeTimeStamp() < p2->GetDataChangeTimeStamp();
305 }
306 };
307 } // end of anonymous namespace
308
ImplCheckSizeOfSwappedInGraphics()309 void GraphicManager::ImplCheckSizeOfSwappedInGraphics()
310 {
311 // only necessary for 32bit systems
312 if(SAL_TYPES_SIZEOFPOINTER <= 4)
313 {
314 // get the currently used memory footprint of all swapped in bitmap graphics
315 // of this graphic manager. Remember candidates in a vector. The size in bytes is
316 // already available, thus this loop is not expensive to execute
317 sal_uLong nUsedSize(0);
318 GraphicObject* pObj = 0;
319 std::vector< GraphicObject* > aCandidates;
320
321 for(pObj = (GraphicObject*)maObjList.First(); pObj; pObj = (GraphicObject*)maObjList.Next())
322 {
323 if(pObj->meType == GRAPHIC_BITMAP && !pObj->IsSwappedOut() && pObj->GetSizeBytes())
324 {
325 aCandidates.push_back(pObj);
326 nUsedSize += pObj->GetSizeBytes();
327 }
328 }
329
330 // detect maximum allowed memory footprint. Use the user-settings of MaxCacheSize (defaulted
331 // to 20MB) and add a decent multiplicator (expecrimented to find one). Limit to
332 // a useful maximum for 32Bit address space
333
334 // default is 20MB, so allow 200MB initially
335 static sal_uLong aMultiplicator(10);
336
337 // max at 500MB; I experimented with 800 for debug and 750 for non-debug settings (pics start
338 // missing when AOO reaches a mem footprint of 1.5GB) but some secure left over space for
339 // app activity is needed
340 static sal_uLong aMaxSize32Bit(500 * 1024 * 1024);
341
342 // calc max allowed cache size
343 const sal_uLong nMaxCacheSize(::std::min(GetMaxCacheSize() * aMultiplicator, aMaxSize32Bit));
344
345 if(nUsedSize >= nMaxCacheSize && !aCandidates.empty())
346 {
347 // if we use more currently, sort by last DataChangeTimeStamp
348 // sort by DataChangeTimeStamp so that the oldest get removed first
349 ::std::sort(aCandidates.begin(), aCandidates.end(), simpleSortByDataChangeTimeStamp());
350
351 for(sal_uInt32 a(0); nUsedSize >= nMaxCacheSize && a < aCandidates.size(); a++)
352 {
353 // swap out until we have no more or the goal to use less than nMaxCacheSize
354 // is reached
355 pObj = aCandidates[a];
356 const sal_uLong nSizeBytes(pObj->GetSizeBytes());
357
358 // do not swap out when we have less than 16KB data objects
359 if(nSizeBytes >= (16 * 1024))
360 {
361 // #125519# need to check if GraphicObject is still alive
362 GraphicObject* pObj2 = 0;
363 bool bExists(false);
364
365 for(pObj2 = (GraphicObject*)maObjList.First(); !bExists && pObj2; pObj2 = (GraphicObject*)maObjList.Next())
366 {
367 if(pObj2 && pObj2 == pObj)
368 {
369 bExists = true;
370 }
371 }
372
373 if(bExists)
374 {
375 // #125519# okay, swap it out
376 pObj->FireSwapOutRequest();
377 nUsedSize = (nSizeBytes < nUsedSize) ? nUsedSize - nSizeBytes : 0;
378 }
379 else
380 {
381 // #125519# error: object was deleted while still a member in aCandidates. This means that
382 // an earlier call to pObj->FireSwapOutRequest() on an other GraphicObject has as
383 // a side effect *deleted* and thus removed another GraphicObject from the local
384 // list (maObjList). This must of course be avoided.
385 // To check without need to run in debugger, optionally temporarily reactivate the beep below
386 // Sound::Beep();
387 }
388 }
389 }
390 }
391 }
392 }
393
394 // -----------------------------------------------------------------------------
395
ImplFillSwappedGraphicObject(const GraphicObject & rObj,Graphic & rSubstitute)396 sal_Bool GraphicManager::ImplFillSwappedGraphicObject( const GraphicObject& rObj, Graphic& rSubstitute )
397 {
398 return mpCache->FillSwappedGraphicObject(rObj, rSubstitute);
399 }
400
401 // -----------------------------------------------------------------------------
402
ImplGraphicObjectWasSwappedIn(const GraphicObject & rObj)403 void GraphicManager::ImplGraphicObjectWasSwappedIn( const GraphicObject& rObj )
404 {
405 mpCache->GraphicObjectWasSwappedIn( rObj );
406 }
407
408 // -----------------------------------------------------------------------------
409
ImplDraw(OutputDevice * pOut,const Point & rPt,const Size & rSz,GraphicObject & rObj,const GraphicAttr & rAttr,const sal_uLong nFlags,sal_Bool & rCached)410 sal_Bool GraphicManager::ImplDraw( OutputDevice* pOut, const Point& rPt,
411 const Size& rSz, GraphicObject& rObj,
412 const GraphicAttr& rAttr,
413 const sal_uLong nFlags, sal_Bool& rCached )
414 {
415 const Graphic& rGraphic = rObj.GetGraphic();
416 sal_Bool bRet = sal_False;
417
418 if( rGraphic.IsSupportedGraphic() && !rGraphic.IsSwapOut() )
419 {
420 if( GRAPHIC_BITMAP == rGraphic.GetType() )
421 {
422 const BitmapEx aSrcBmpEx( rGraphic.GetBitmapEx() );
423
424 // #i46805# No point in caching a bitmap that is rendered
425 // via RectFill on the OutDev
426 if( !(pOut->GetDrawMode() & ( DRAWMODE_BLACKBITMAP | DRAWMODE_WHITEBITMAP )) &&
427 mpCache->IsDisplayCacheable( pOut, rPt, rSz, rObj, rAttr ) )
428 {
429 BitmapEx aDstBmpEx;
430
431 if( ImplCreateOutput( pOut, rPt, rSz, aSrcBmpEx, rAttr, nFlags, &aDstBmpEx ) )
432 {
433 rCached = mpCache->CreateDisplayCacheObj( pOut, rPt, rSz, rObj, rAttr, aDstBmpEx );
434 bRet = sal_True;
435 }
436 }
437
438 if( !bRet )
439 bRet = ImplCreateOutput( pOut, rPt, rSz, aSrcBmpEx, rAttr, nFlags );
440 }
441 else
442 {
443 const GDIMetaFile& rSrcMtf = rGraphic.GetGDIMetaFile();
444
445 if( mpCache->IsDisplayCacheable( pOut, rPt, rSz, rObj, rAttr ) )
446 {
447 GDIMetaFile aDstMtf;
448 BitmapEx aContainedBmpEx;
449
450 if( ImplCreateOutput( pOut, rPt, rSz, rSrcMtf, rAttr, nFlags, aDstMtf, aContainedBmpEx ) )
451 {
452 if( !!aContainedBmpEx )
453 {
454 // #117889# Use bitmap output method, if
455 // metafile basically contains only a single
456 // bitmap
457 BitmapEx aDstBmpEx;
458
459 if( ImplCreateOutput( pOut, rPt, rSz, aContainedBmpEx, rAttr, nFlags, &aDstBmpEx ) )
460 {
461 rCached = mpCache->CreateDisplayCacheObj( pOut, rPt, rSz, rObj, rAttr, aDstBmpEx );
462 bRet = sal_True;
463 }
464 }
465 else
466 {
467 rCached = mpCache->CreateDisplayCacheObj( pOut, rPt, rSz, rObj, rAttr, aDstMtf );
468 bRet = sal_True;
469 }
470 }
471 }
472
473 if( !bRet )
474 {
475 const Graphic aGraphic( rObj.GetTransformedGraphic( &rAttr ) );
476
477 if( aGraphic.IsSupportedGraphic() )
478 {
479 aGraphic.Draw( pOut, rPt, rSz );
480 bRet = sal_True;
481 }
482 }
483 }
484 }
485
486 return bRet;
487 }
488
489 // -----------------------------------------------------------------------------
490
ImplCreateOutput(OutputDevice * pOut,const Point & rPt,const Size & rSz,const BitmapEx & rBmpEx,const GraphicAttr & rAttr,const sal_uLong nFlags,BitmapEx * pBmpEx)491 sal_Bool GraphicManager::ImplCreateOutput( OutputDevice* pOut,
492 const Point& rPt, const Size& rSz,
493 const BitmapEx& rBmpEx, const GraphicAttr& rAttr,
494 const sal_uLong nFlags, BitmapEx* pBmpEx )
495 {
496 sal_uInt16 nRot10 = rAttr.GetRotation() % 3600;
497 Point aOutPtPix;
498 Size aOutSzPix;
499 Size aUnrotatedSzPix( pOut->LogicToPixel( rSz ) );
500 sal_Bool bRet = sal_False;
501
502 if( nRot10 )
503 {
504 Polygon aPoly( Rectangle( rPt, rSz ) );
505
506 aPoly.Rotate( rPt, nRot10 );
507 const Rectangle aRotBoundRect( aPoly.GetBoundRect() );
508 aOutPtPix = pOut->LogicToPixel( aRotBoundRect.TopLeft() );
509 aOutSzPix = pOut->LogicToPixel( aRotBoundRect.GetSize() );
510 }
511 else
512 {
513 aOutPtPix = pOut->LogicToPixel( rPt );
514 aOutSzPix = aUnrotatedSzPix;
515 }
516
517 if( aUnrotatedSzPix.Width() && aUnrotatedSzPix.Height() )
518 {
519 BitmapEx aBmpEx( rBmpEx );
520 BitmapEx aOutBmpEx;
521 Point aOutPt;
522 Size aOutSz;
523 const Size& rBmpSzPix = rBmpEx.GetSizePixel();
524 const long nW = rBmpSzPix.Width();
525 const long nH = rBmpSzPix.Height();
526 const long nNewW = aUnrotatedSzPix.Width();
527 const long nNewH = aUnrotatedSzPix.Height();
528 double fTmp;
529 long* pMapIX = new long[ nNewW ];
530 long* pMapFX = new long[ nNewW ];
531 long* pMapIY = new long[ nNewH ];
532 long* pMapFY = new long[ nNewH ];
533 long nStartX = -1, nStartY = -1, nEndX = -1, nEndY = -1;
534 long nX, nY, nTmp, nTmpX, nTmpY;
535 sal_Bool bHMirr = ( rAttr.GetMirrorFlags() & BMP_MIRROR_HORZ ) != 0;
536 sal_Bool bVMirr = ( rAttr.GetMirrorFlags() & BMP_MIRROR_VERT ) != 0;
537
538 if( nFlags & GRFMGR_DRAW_BILINEAR )
539 {
540 const double fRevScaleX = ( nNewW > 1L ) ? ( (double) ( nW - 1L ) / ( nNewW - 1L ) ) : 0.0;
541 const double fRevScaleY = ( nNewH > 1L ) ? ( (double) ( nH - 1L ) / ( nNewH - 1L ) ) : 0.0;
542
543 // create horizontal mapping table
544 for( nX = 0L, nTmpX = nW - 1L, nTmp = nW - 2L; nX < nNewW; nX++ )
545 {
546 fTmp = nX * fRevScaleX;
547
548 if( bHMirr )
549 fTmp = nTmpX - fTmp;
550
551 pMapFX[ nX ] = (long) ( ( fTmp - ( pMapIX[ nX ] = MinMax( (long) fTmp, 0, nTmp ) ) ) * 1048576. );
552 }
553
554 // create vertical mapping table
555 for( nY = 0L, nTmpY = nH - 1L, nTmp = nH - 2L; nY < nNewH; nY++ )
556 {
557 fTmp = nY * fRevScaleY;
558
559 if( bVMirr )
560 fTmp = nTmpY - fTmp;
561
562 pMapFY[ nY ] = (long) ( ( fTmp - ( pMapIY[ nY ] = MinMax( (long) fTmp, 0, nTmp ) ) ) * 1048576. );
563 }
564 }
565 else
566 {
567 // #98290# Use a different mapping for non-interpolating mode, to avoid missing rows/columns
568 const double fRevScaleX = ( nNewW > 1L ) ? ( (double) nW / nNewW ) : 0.0;
569 const double fRevScaleY = ( nNewH > 1L ) ? ( (double) nH / nNewH ) : 0.0;
570
571 // create horizontal mapping table
572 for( nX = 0L, nTmpX = nW - 1L, nTmp = nW - 2L; nX < nNewW; nX++ )
573 {
574 fTmp = nX * fRevScaleX;
575
576 if( bHMirr )
577 fTmp = nTmpX - fTmp;
578
579 // #98290# Do not use round to zero, otherwise last column will be missing
580 pMapIX[ nX ] = MinMax( (long) fTmp, 0, nTmp );
581 pMapFX[ nX ] = fTmp >= nTmp+1 ? 1048576 : 0;
582 }
583
584 // create vertical mapping table
585 for( nY = 0L, nTmpY = nH - 1L, nTmp = nH - 2L; nY < nNewH; nY++ )
586 {
587 fTmp = nY * fRevScaleY;
588
589 if( bVMirr )
590 fTmp = nTmpY - fTmp;
591
592 // #98290# Do not use round to zero, otherwise last row will be missing
593 pMapIY[ nY ] = MinMax( (long) fTmp, 0, nTmp );
594 pMapFY[ nY ] = fTmp >= nTmp+1 ? 1048576 : 0;
595 }
596 }
597
598 // calculate output sizes
599 if( !pBmpEx )
600 {
601 Point aPt;
602 Rectangle aOutRect( aPt, pOut->GetOutputSizePixel() );
603 Rectangle aBmpRect( aOutPtPix, aOutSzPix );
604
605 if( pOut->GetOutDevType() == OUTDEV_WINDOW )
606 {
607 const Region aPaintRgn( ( (Window*) pOut )->GetPaintRegion() );
608 if( !aPaintRgn.IsNull() )
609 aOutRect.Intersection( pOut->LogicToPixel( aPaintRgn.GetBoundRect() ) );
610 }
611
612 aOutRect.Intersection( aBmpRect );
613
614 if( !aOutRect.IsEmpty() )
615 {
616 aOutPt = pOut->PixelToLogic( aOutRect.TopLeft() );
617 aOutSz = pOut->PixelToLogic( aOutRect.GetSize() );
618 nStartX = aOutRect.Left() - aBmpRect.Left();
619 nStartY = aOutRect.Top() - aBmpRect.Top();
620 nEndX = aOutRect.Right() - aBmpRect.Left();
621 nEndY = aOutRect.Bottom() - aBmpRect.Top();
622 }
623 else
624 nStartX = -1L; // invalid
625 }
626 else
627 {
628 aOutPt = pOut->PixelToLogic( aOutPtPix );
629 aOutSz = pOut->PixelToLogic( aOutSzPix );
630 nStartX = nStartY = 0;
631 nEndX = aOutSzPix.Width() - 1L;
632 nEndY = aOutSzPix.Height() - 1L;
633 }
634
635 // do transformation
636 if( nStartX >= 0L )
637 {
638 const sal_Bool bSimple = ( 1 == nW || 1 == nH );
639
640 if( nRot10 )
641 {
642 if( bSimple )
643 {
644 bRet = ( aOutBmpEx = aBmpEx ).Scale( aUnrotatedSzPix );
645
646 if( bRet )
647 aOutBmpEx.Rotate( nRot10, COL_TRANSPARENT );
648 }
649 else
650 {
651 bRet = ImplCreateRotatedScaled( aBmpEx,
652 nRot10, aOutSzPix, aUnrotatedSzPix,
653 pMapIX, pMapFX, pMapIY, pMapFY, nStartX, nEndX, nStartY, nEndY,
654 aOutBmpEx );
655 }
656 }
657 else
658 {
659 // #105229# Don't scale if output size equals bitmap size
660 // #107226# Copy through only if we're not mirroring
661 if( !bHMirr && !bVMirr && aOutSzPix == rBmpSzPix )
662 {
663 // #107226# Use original dimensions when just copying through
664 aOutPt = pOut->PixelToLogic( aOutPtPix );
665 aOutSz = pOut->PixelToLogic( aOutSzPix );
666 aOutBmpEx = aBmpEx;
667 bRet = sal_True;
668 }
669 else
670 {
671 if( bSimple )
672 bRet = ( aOutBmpEx = aBmpEx ).Scale( Size( nEndX - nStartX + 1, nEndY - nStartY + 1 ) );
673 else
674 {
675 bRet = ImplCreateScaled( aBmpEx,
676 pMapIX, pMapFX, pMapIY, pMapFY,
677 nStartX, nEndX, nStartY, nEndY,
678 aOutBmpEx );
679 }
680 }
681 }
682
683 if( bRet )
684 {
685 // attribute adjustment if neccessary
686 if( rAttr.IsSpecialDrawMode() || rAttr.IsAdjusted() || rAttr.IsTransparent() )
687 ImplAdjust( aOutBmpEx, rAttr, ADJUSTMENT_DRAWMODE | ADJUSTMENT_COLORS | ADJUSTMENT_TRANSPARENCY );
688
689 // OutDev adjustment if neccessary
690 if( pOut->GetOutDevType() != OUTDEV_PRINTER && pOut->GetBitCount() <= 8 && aOutBmpEx.GetBitCount() >= 8 )
691 aOutBmpEx.Dither( BMP_DITHER_MATRIX );
692 }
693 }
694
695 // delete lookup tables
696 delete[] pMapIX;
697 delete[] pMapFX;
698 delete[] pMapIY;
699 delete[] pMapFY;
700
701 // create output
702 if( bRet )
703 {
704 if( !pBmpEx )
705 pOut->DrawBitmapEx( aOutPt, aOutSz, aOutBmpEx );
706 else
707 {
708 if( !rAttr.IsTransparent() && !aOutBmpEx.IsAlpha() )
709 aOutBmpEx = BitmapEx( aOutBmpEx.GetBitmap().CreateDisplayBitmap( pOut ), aOutBmpEx.GetMask() );
710
711 pOut->DrawBitmapEx( aOutPt, aOutSz, *pBmpEx = aOutBmpEx );
712 }
713 }
714 }
715
716 return bRet;
717 }
718
719 // -----------------------------------------------------------------------------
720
ImplCreateOutput(OutputDevice * pOut,const Point & rPt,const Size & rSz,const GDIMetaFile & rMtf,const GraphicAttr & rAttr,const sal_uLong,GDIMetaFile & rOutMtf,BitmapEx & rOutBmpEx)721 sal_Bool GraphicManager::ImplCreateOutput( OutputDevice* pOut,
722 const Point& rPt, const Size& rSz,
723 const GDIMetaFile& rMtf, const GraphicAttr& rAttr,
724 const sal_uLong /*nFlags*/, GDIMetaFile& rOutMtf, BitmapEx& rOutBmpEx )
725 {
726 const Size aNewSize( rMtf.GetPrefSize() );
727
728 rOutMtf = rMtf;
729
730 // #117889# count bitmap actions, and flag actions that paint, but
731 // are no bitmaps.
732 sal_Int32 nNumBitmaps(0);
733 bool bNonBitmapActionEncountered(false);
734 if( aNewSize.Width() && aNewSize.Height() && rSz.Width() && rSz.Height() )
735 {
736 const double fGrfWH = (double) aNewSize.Width() / aNewSize.Height();
737 const double fOutWH = (double) rSz.Width() / rSz.Height();
738
739 const double fScaleX = fOutWH / fGrfWH;
740 const double fScaleY = 1.0;
741
742 const MapMode& rPrefMapMode( rMtf.GetPrefMapMode() );
743 const Size& rSizePix( pOut->LogicToPixel( aNewSize,
744 rPrefMapMode ) );
745
746 // taking care of font width default if scaling metafile.
747 // #117889# use existing metafile scan, to determine whether
748 // the metafile basically displays a single bitmap. Note that
749 // the solution, as implemented here, is quite suboptimal (the
750 // cases where a mtf consisting basically of a single bitmap,
751 // that fail to pass the test below, are probably frequent). A
752 // better solution would involve FSAA, but that's currently
753 // expensive, and might trigger bugs on display drivers, if
754 // VDevs get bigger than the actual screen.
755 sal_uInt32 nCurPos;
756 MetaAction* pAct;
757 for( nCurPos = 0, pAct = (MetaAction*)rOutMtf.FirstAction(); pAct;
758 pAct = (MetaAction*)rOutMtf.NextAction(), nCurPos++ )
759 {
760 MetaAction* pModAct = NULL;
761 switch( pAct->GetType() )
762 {
763 case META_FONT_ACTION:
764 {
765 MetaFontAction* pA = (MetaFontAction*)pAct;
766 Font aFont( pA->GetFont() );
767 if ( !aFont.GetWidth() )
768 {
769 FontMetric aFontMetric( pOut->GetFontMetric( aFont ) );
770 aFont.SetWidth( aFontMetric.GetWidth() );
771 pModAct = new MetaFontAction( aFont );
772 }
773 }
774 // FALLTHROUGH intended
775 case META_NULL_ACTION:
776 // FALLTHROUGH intended
777
778 // OutDev state changes (which don't affect bitmap
779 // output)
780 case META_LINECOLOR_ACTION:
781 // FALLTHROUGH intended
782 case META_FILLCOLOR_ACTION:
783 // FALLTHROUGH intended
784 case META_TEXTCOLOR_ACTION:
785 // FALLTHROUGH intended
786 case META_TEXTFILLCOLOR_ACTION:
787 // FALLTHROUGH intended
788 case META_TEXTALIGN_ACTION:
789 // FALLTHROUGH intended
790 case META_TEXTLINECOLOR_ACTION:
791 // FALLTHROUGH intended
792 case META_TEXTLINE_ACTION:
793 // FALLTHROUGH intended
794 case META_PUSH_ACTION:
795 // FALLTHROUGH intended
796 case META_POP_ACTION:
797 // FALLTHROUGH intended
798 case META_LAYOUTMODE_ACTION:
799 // FALLTHROUGH intended
800 case META_TEXTLANGUAGE_ACTION:
801 // FALLTHROUGH intended
802 case META_COMMENT_ACTION:
803 break;
804
805 // bitmap output methods
806 case META_BMP_ACTION:
807 if( !nNumBitmaps && !bNonBitmapActionEncountered )
808 {
809 MetaBmpAction* pAction = (MetaBmpAction*)pAct;
810
811 rOutBmpEx = BitmapEx( pAction->GetBitmap() );
812 muckWithBitmap( pOut->LogicToPixel( pAction->GetPoint(),
813 rPrefMapMode ),
814 pAction->GetBitmap().GetSizePixel(),
815 rSizePix,
816 bNonBitmapActionEncountered );
817 ++nNumBitmaps;
818 }
819 break;
820
821 case META_BMPSCALE_ACTION:
822 if( !nNumBitmaps && !bNonBitmapActionEncountered )
823 {
824 MetaBmpScaleAction* pAction = (MetaBmpScaleAction*)pAct;
825
826 rOutBmpEx = BitmapEx( pAction->GetBitmap() );
827 muckWithBitmap( pOut->LogicToPixel( pAction->GetPoint(),
828 rPrefMapMode ),
829 pOut->LogicToPixel( pAction->GetSize(),
830 rPrefMapMode ),
831 rSizePix,
832 bNonBitmapActionEncountered );
833 ++nNumBitmaps;
834 }
835 break;
836
837 case META_BMPSCALEPART_ACTION:
838 if( !nNumBitmaps && !bNonBitmapActionEncountered )
839 {
840 MetaBmpScalePartAction* pAction = (MetaBmpScalePartAction*)pAct;
841
842 rOutBmpEx = muckWithBitmap( BitmapEx( pAction->GetBitmap() ),
843 pAction->GetSrcPoint(),
844 pAction->GetSrcSize(),
845 pOut->LogicToPixel( pAction->GetDestPoint(),
846 rPrefMapMode ),
847 pOut->LogicToPixel( pAction->GetDestSize(),
848 rPrefMapMode ),
849 rSizePix,
850 bNonBitmapActionEncountered );
851 ++nNumBitmaps;
852 }
853 break;
854
855 case META_BMPEX_ACTION:
856 if( !nNumBitmaps && !bNonBitmapActionEncountered )
857 {
858 MetaBmpExAction* pAction = (MetaBmpExAction*)pAct;
859
860 rOutBmpEx = pAction->GetBitmapEx();
861 muckWithBitmap( pOut->LogicToPixel( pAction->GetPoint(),
862 rPrefMapMode ),
863 pAction->GetBitmapEx().GetSizePixel(),
864 rSizePix,
865 bNonBitmapActionEncountered );
866 ++nNumBitmaps;
867 }
868 break;
869
870 case META_BMPEXSCALE_ACTION:
871 if( !nNumBitmaps && !bNonBitmapActionEncountered )
872 {
873 MetaBmpExScaleAction* pAction = (MetaBmpExScaleAction*)pAct;
874
875 rOutBmpEx = pAction->GetBitmapEx();
876 muckWithBitmap( pOut->LogicToPixel( pAction->GetPoint(),
877 rPrefMapMode ),
878 pOut->LogicToPixel( pAction->GetSize(),
879 rPrefMapMode ),
880 rSizePix,
881 bNonBitmapActionEncountered );
882 ++nNumBitmaps;
883 }
884 break;
885
886 case META_BMPEXSCALEPART_ACTION:
887 if( !nNumBitmaps && !bNonBitmapActionEncountered )
888 {
889 MetaBmpExScalePartAction* pAction = (MetaBmpExScalePartAction*)pAct;
890
891 rOutBmpEx = muckWithBitmap( pAction->GetBitmapEx(),
892 pAction->GetSrcPoint(),
893 pAction->GetSrcSize(),
894 pOut->LogicToPixel( pAction->GetDestPoint(),
895 rPrefMapMode ),
896 pOut->LogicToPixel( pAction->GetDestSize(),
897 rPrefMapMode ),
898 rSizePix,
899 bNonBitmapActionEncountered );
900 ++nNumBitmaps;
901 }
902 break;
903
904 // these actions actually output something (that's
905 // different from a bitmap)
906 case META_RASTEROP_ACTION:
907 if( ((MetaRasterOpAction*)pAct)->GetRasterOp() == ROP_OVERPAINT )
908 break;
909 // FALLTHROUGH intended
910 case META_PIXEL_ACTION:
911 // FALLTHROUGH intended
912 case META_POINT_ACTION:
913 // FALLTHROUGH intended
914 case META_LINE_ACTION:
915 // FALLTHROUGH intended
916 case META_RECT_ACTION:
917 // FALLTHROUGH intended
918 case META_ROUNDRECT_ACTION:
919 // FALLTHROUGH intended
920 case META_ELLIPSE_ACTION:
921 // FALLTHROUGH intended
922 case META_ARC_ACTION:
923 // FALLTHROUGH intended
924 case META_PIE_ACTION:
925 // FALLTHROUGH intended
926 case META_CHORD_ACTION:
927 // FALLTHROUGH intended
928 case META_POLYLINE_ACTION:
929 // FALLTHROUGH intended
930 case META_POLYGON_ACTION:
931 // FALLTHROUGH intended
932 case META_POLYPOLYGON_ACTION:
933 // FALLTHROUGH intended
934
935 case META_TEXT_ACTION:
936 // FALLTHROUGH intended
937 case META_TEXTARRAY_ACTION:
938 // FALLTHROUGH intended
939 case META_STRETCHTEXT_ACTION:
940 // FALLTHROUGH intended
941 case META_TEXTRECT_ACTION:
942 // FALLTHROUGH intended
943
944 case META_MASK_ACTION:
945 // FALLTHROUGH intended
946 case META_MASKSCALE_ACTION:
947 // FALLTHROUGH intended
948 case META_MASKSCALEPART_ACTION:
949 // FALLTHROUGH intended
950
951 case META_GRADIENT_ACTION:
952 // FALLTHROUGH intended
953 case META_HATCH_ACTION:
954 // FALLTHROUGH intended
955 case META_WALLPAPER_ACTION:
956 // FALLTHROUGH intended
957
958 case META_TRANSPARENT_ACTION:
959 // FALLTHROUGH intended
960 case META_EPS_ACTION:
961 // FALLTHROUGH intended
962 case META_FLOATTRANSPARENT_ACTION:
963 // FALLTHROUGH intended
964 case META_GRADIENTEX_ACTION:
965 // FALLTHROUGH intended
966
967 // OutDev state changes that _do_ affect bitmap
968 // output
969 case META_CLIPREGION_ACTION:
970 // FALLTHROUGH intended
971 case META_ISECTRECTCLIPREGION_ACTION:
972 // FALLTHROUGH intended
973 case META_ISECTREGIONCLIPREGION_ACTION:
974 // FALLTHROUGH intended
975 case META_MOVECLIPREGION_ACTION:
976 // FALLTHROUGH intended
977
978 case META_MAPMODE_ACTION:
979 // FALLTHROUGH intended
980 case META_REFPOINT_ACTION:
981 // FALLTHROUGH intended
982 default:
983 bNonBitmapActionEncountered = true;
984 break;
985 }
986 if ( pModAct )
987 {
988 rOutMtf.ReplaceAction( pModAct, nCurPos );
989 pAct->Delete();
990 }
991 else
992 {
993 if( pAct->GetRefCount() > 1 )
994 {
995 rOutMtf.ReplaceAction( pModAct = pAct->Clone(), nCurPos );
996 pAct->Delete();
997 }
998 else
999 pModAct = pAct;
1000 }
1001 pModAct->Scale( fScaleX, fScaleY );
1002 }
1003 rOutMtf.SetPrefSize( Size( FRound( aNewSize.Width() * fScaleX ),
1004 FRound( aNewSize.Height() * fScaleY ) ) );
1005 }
1006
1007 if( nNumBitmaps != 1 || bNonBitmapActionEncountered )
1008 {
1009 if( rAttr.IsSpecialDrawMode() || rAttr.IsAdjusted() || rAttr.IsMirrored() || rAttr.IsRotated() || rAttr.IsTransparent() )
1010 ImplAdjust( rOutMtf, rAttr, ADJUSTMENT_ALL );
1011
1012 ImplDraw( pOut, rPt, rSz, rOutMtf, rAttr );
1013 rOutBmpEx = BitmapEx();
1014 }
1015
1016 return sal_True;
1017 }
1018
1019 // -----------------------------------------------------------------------------
1020
ImplCreateScaled(const BitmapEx & rBmpEx,long * pMapIX,long * pMapFX,long * pMapIY,long * pMapFY,long nStartX,long nEndX,long nStartY,long nEndY,BitmapEx & rOutBmpEx)1021 sal_Bool GraphicManager::ImplCreateScaled( const BitmapEx& rBmpEx,
1022 long* pMapIX, long* pMapFX, long* pMapIY, long* pMapFY,
1023 long nStartX, long nEndX, long nStartY, long nEndY,
1024 BitmapEx& rOutBmpEx )
1025 {
1026 Bitmap aBmp( rBmpEx.GetBitmap() );
1027 Bitmap aOutBmp;
1028 BitmapReadAccess* pAcc = aBmp.AcquireReadAccess();
1029 BitmapWriteAccess* pWAcc;
1030 BitmapColor aCol0, aCol1, aColRes;
1031 const long nDstW = nEndX - nStartX + 1L;
1032 const long nDstH = nEndY - nStartY + 1L;
1033 long nX, nY, nTmpX, nTmpY, nTmpFX, nTmpFY;
1034 long nXDst, nYDst;
1035 sal_uInt8 cR0, cG0, cB0, cR1, cG1, cB1;
1036 sal_Bool bRet = sal_False;
1037
1038 DBG_ASSERT( aBmp.GetSizePixel() == rBmpEx.GetSizePixel(),
1039 "GraphicManager::ImplCreateScaled(): bmp size inconsistent" );
1040
1041 if( pAcc )
1042 {
1043 aOutBmp = Bitmap( Size( nDstW, nDstH ), 24 );
1044 pWAcc = aOutBmp.AcquireWriteAccess();
1045
1046 if( pWAcc )
1047 {
1048 if( pAcc->HasPalette() )
1049 {
1050 if( pAcc->GetScanlineFormat() == BMP_FORMAT_8BIT_PAL )
1051 {
1052 Scanline pLine0, pLine1;
1053
1054 for( nY = nStartY, nYDst = 0L; nY <= nEndY; nY++, nYDst++ )
1055 {
1056 nTmpY = pMapIY[ nY ]; nTmpFY = pMapFY[ nY ];
1057 pLine0 = pAcc->GetScanline( nTmpY );
1058 pLine1 = pAcc->GetScanline( ++nTmpY );
1059
1060 for( nX = nStartX, nXDst = 0L; nX <= nEndX; nX++ )
1061 {
1062 nTmpX = pMapIX[ nX ]; nTmpFX = pMapFX[ nX ];
1063
1064 const BitmapColor& rCol0 = pAcc->GetPaletteColor( pLine0[ nTmpX ] );
1065 const BitmapColor& rCol2 = pAcc->GetPaletteColor( pLine1[ nTmpX ] );
1066 const BitmapColor& rCol1 = pAcc->GetPaletteColor( pLine0[ ++nTmpX ] );
1067 const BitmapColor& rCol3 = pAcc->GetPaletteColor( pLine1[ nTmpX ] );
1068
1069 cR0 = MAP( rCol0.GetRed(), rCol1.GetRed(), nTmpFX );
1070 cG0 = MAP( rCol0.GetGreen(), rCol1.GetGreen(), nTmpFX );
1071 cB0 = MAP( rCol0.GetBlue(), rCol1.GetBlue(), nTmpFX );
1072
1073 cR1 = MAP( rCol2.GetRed(), rCol3.GetRed(), nTmpFX );
1074 cG1 = MAP( rCol2.GetGreen(), rCol3.GetGreen(), nTmpFX );
1075 cB1 = MAP( rCol2.GetBlue(), rCol3.GetBlue(), nTmpFX );
1076
1077 aColRes.SetRed( MAP( cR0, cR1, nTmpFY ) );
1078 aColRes.SetGreen( MAP( cG0, cG1, nTmpFY ) );
1079 aColRes.SetBlue( MAP( cB0, cB1, nTmpFY ) );
1080 pWAcc->SetPixel( nYDst, nXDst++, aColRes );
1081 }
1082 }
1083 }
1084 else
1085 {
1086 for( nY = nStartY, nYDst = 0L; nY <= nEndY; nY++, nYDst++ )
1087 {
1088 nTmpY = pMapIY[ nY ], nTmpFY = pMapFY[ nY ];
1089
1090 for( nX = nStartX, nXDst = 0L; nX <= nEndX; nX++ )
1091 {
1092 nTmpX = pMapIX[ nX ]; nTmpFX = pMapFX[ nX ];
1093
1094 aCol0 = pAcc->GetPaletteColor( pAcc->GetPixelIndex( nTmpY, nTmpX ) );
1095 aCol1 = pAcc->GetPaletteColor( pAcc->GetPixelIndex( nTmpY, ++nTmpX ) );
1096 cR0 = MAP( aCol0.GetRed(), aCol1.GetRed(), nTmpFX );
1097 cG0 = MAP( aCol0.GetGreen(), aCol1.GetGreen(), nTmpFX );
1098 cB0 = MAP( aCol0.GetBlue(), aCol1.GetBlue(), nTmpFX );
1099
1100 aCol1 = pAcc->GetPaletteColor( pAcc->GetPixelIndex( ++nTmpY, nTmpX ) );
1101 aCol0 = pAcc->GetPaletteColor( pAcc->GetPixelIndex( nTmpY--, --nTmpX ) );
1102 cR1 = MAP( aCol0.GetRed(), aCol1.GetRed(), nTmpFX );
1103 cG1 = MAP( aCol0.GetGreen(), aCol1.GetGreen(), nTmpFX );
1104 cB1 = MAP( aCol0.GetBlue(), aCol1.GetBlue(), nTmpFX );
1105
1106 aColRes.SetRed( MAP( cR0, cR1, nTmpFY ) );
1107 aColRes.SetGreen( MAP( cG0, cG1, nTmpFY ) );
1108 aColRes.SetBlue( MAP( cB0, cB1, nTmpFY ) );
1109 pWAcc->SetPixel( nYDst, nXDst++, aColRes );
1110 }
1111 }
1112 }
1113 }
1114 else
1115 {
1116 if( pAcc->GetScanlineFormat() == BMP_FORMAT_24BIT_TC_BGR )
1117 {
1118 Scanline pLine0, pLine1, pTmp0, pTmp1;
1119 long nOff;
1120
1121 for( nY = nStartY, nYDst = 0L; nY <= nEndY; nY++, nYDst++ )
1122 {
1123 nTmpY = pMapIY[ nY ]; nTmpFY = pMapFY[ nY ];
1124 pLine0 = pAcc->GetScanline( nTmpY );
1125 pLine1 = pAcc->GetScanline( ++nTmpY );
1126
1127 for( nX = nStartX, nXDst = 0L; nX <= nEndX; nX++ )
1128 {
1129 nOff = 3L * ( nTmpX = pMapIX[ nX ] );
1130 nTmpFX = pMapFX[ nX ];
1131
1132 pTmp1 = ( pTmp0 = pLine0 + nOff ) + 3L;
1133 cB0 = MAP( *pTmp0, *pTmp1, nTmpFX ); pTmp0++; pTmp1++;
1134 cG0 = MAP( *pTmp0, *pTmp1, nTmpFX ); pTmp0++; pTmp1++;
1135 cR0 = MAP( *pTmp0, *pTmp1, nTmpFX );
1136
1137 pTmp1 = ( pTmp0 = pLine1 + nOff ) + 3L;
1138 cB1 = MAP( *pTmp0, *pTmp1, nTmpFX ); pTmp0++; pTmp1++;
1139 cG1 = MAP( *pTmp0, *pTmp1, nTmpFX ); pTmp0++; pTmp1++;
1140 cR1 = MAP( *pTmp0, *pTmp1, nTmpFX );
1141
1142 aColRes.SetRed( MAP( cR0, cR1, nTmpFY ) );
1143 aColRes.SetGreen( MAP( cG0, cG1, nTmpFY ) );
1144 aColRes.SetBlue( MAP( cB0, cB1, nTmpFY ) );
1145 pWAcc->SetPixel( nYDst, nXDst++, aColRes );
1146 }
1147 }
1148 }
1149 else if( pAcc->GetScanlineFormat() == BMP_FORMAT_24BIT_TC_RGB )
1150 {
1151 Scanline pLine0, pLine1, pTmp0, pTmp1;
1152 long nOff;
1153
1154 for( nY = nStartY, nYDst = 0L; nY <= nEndY; nY++, nYDst++ )
1155 {
1156 nTmpY = pMapIY[ nY ]; nTmpFY = pMapFY[ nY ];
1157 pLine0 = pAcc->GetScanline( nTmpY );
1158 pLine1 = pAcc->GetScanline( ++nTmpY );
1159
1160 for( nX = nStartX, nXDst = 0L; nX <= nEndX; nX++ )
1161 {
1162 nOff = 3L * ( nTmpX = pMapIX[ nX ] );
1163 nTmpFX = pMapFX[ nX ];
1164
1165 pTmp1 = ( pTmp0 = pLine0 + nOff ) + 3L;
1166 cR0 = MAP( *pTmp0, *pTmp1, nTmpFX ); pTmp0++; pTmp1++;
1167 cG0 = MAP( *pTmp0, *pTmp1, nTmpFX ); pTmp0++; pTmp1++;
1168 cB0 = MAP( *pTmp0, *pTmp1, nTmpFX );
1169
1170 pTmp1 = ( pTmp0 = pLine1 + nOff ) + 3L;
1171 cR1 = MAP( *pTmp0, *pTmp1, nTmpFX ); pTmp0++; pTmp1++;
1172 cG1 = MAP( *pTmp0, *pTmp1, nTmpFX ); pTmp0++; pTmp1++;
1173 cB1 = MAP( *pTmp0, *pTmp1, nTmpFX );
1174
1175 aColRes.SetRed( MAP( cR0, cR1, nTmpFY ) );
1176 aColRes.SetGreen( MAP( cG0, cG1, nTmpFY ) );
1177 aColRes.SetBlue( MAP( cB0, cB1, nTmpFY ) );
1178 pWAcc->SetPixel( nYDst, nXDst++, aColRes );
1179 }
1180 }
1181 }
1182 else
1183 {
1184 for( nY = nStartY, nYDst = 0L; nY <= nEndY; nY++, nYDst++ )
1185 {
1186 nTmpY = pMapIY[ nY ]; nTmpFY = pMapFY[ nY ];
1187
1188 for( nX = nStartX, nXDst = 0L; nX <= nEndX; nX++ )
1189 {
1190 nTmpX = pMapIX[ nX ]; nTmpFX = pMapFX[ nX ];
1191
1192 aCol0 = pAcc->GetPixel( nTmpY, nTmpX );
1193 aCol1 = pAcc->GetPixel( nTmpY, ++nTmpX );
1194 cR0 = MAP( aCol0.GetRed(), aCol1.GetRed(), nTmpFX );
1195 cG0 = MAP( aCol0.GetGreen(), aCol1.GetGreen(), nTmpFX );
1196 cB0 = MAP( aCol0.GetBlue(), aCol1.GetBlue(), nTmpFX );
1197
1198 aCol1 = pAcc->GetPixel( ++nTmpY, nTmpX );
1199 aCol0 = pAcc->GetPixel( nTmpY--, --nTmpX );
1200 cR1 = MAP( aCol0.GetRed(), aCol1.GetRed(), nTmpFX );
1201 cG1 = MAP( aCol0.GetGreen(), aCol1.GetGreen(), nTmpFX );
1202 cB1 = MAP( aCol0.GetBlue(), aCol1.GetBlue(), nTmpFX );
1203
1204 aColRes.SetRed( MAP( cR0, cR1, nTmpFY ) );
1205 aColRes.SetGreen( MAP( cG0, cG1, nTmpFY ) );
1206 aColRes.SetBlue( MAP( cB0, cB1, nTmpFY ) );
1207 pWAcc->SetPixel( nYDst, nXDst++, aColRes );
1208 }
1209 }
1210 }
1211 }
1212
1213 aOutBmp.ReleaseAccess( pWAcc );
1214 bRet = sal_True;
1215 }
1216
1217 aBmp.ReleaseAccess( pAcc );
1218 }
1219
1220 if( bRet && rBmpEx.IsTransparent() )
1221 {
1222 bRet = sal_False;
1223
1224 if( rBmpEx.IsAlpha() )
1225 {
1226 DBG_ASSERT( rBmpEx.GetAlpha().GetSizePixel() == rBmpEx.GetSizePixel(),
1227 "GraphicManager::ImplCreateScaled(): alpha mask size inconsistent" );
1228
1229 AlphaMask aAlpha( rBmpEx.GetAlpha() );
1230 AlphaMask aOutAlpha;
1231
1232 pAcc = aAlpha.AcquireReadAccess();
1233
1234 if( pAcc )
1235 {
1236 aOutAlpha = AlphaMask( Size( nDstW, nDstH ) );
1237 pWAcc = aOutAlpha.AcquireWriteAccess();
1238
1239 if( pWAcc )
1240 {
1241 if( pAcc->GetScanlineFormat() == BMP_FORMAT_8BIT_PAL &&
1242 pWAcc->GetScanlineFormat() == BMP_FORMAT_8BIT_PAL )
1243 {
1244 Scanline pLine0, pLine1, pLineW;
1245
1246 for( nY = nStartY, nYDst = 0L; nY <= nEndY; nY++, nYDst++ )
1247 {
1248 nTmpY = pMapIY[ nY ]; nTmpFY = pMapFY[ nY ];
1249 pLine0 = pAcc->GetScanline( nTmpY );
1250 pLine1 = pAcc->GetScanline( ++nTmpY );
1251 pLineW = pWAcc->GetScanline( nYDst );
1252
1253 for( nX = nStartX, nXDst = 0L; nX <= nEndX; nX++, nXDst++ )
1254 {
1255 nTmpX = pMapIX[ nX ]; nTmpFX = pMapFX[ nX ];
1256
1257 const long nAlpha0 = pLine0[ nTmpX ];
1258 const long nAlpha2 = pLine1[ nTmpX ];
1259 const long nAlpha1 = pLine0[ ++nTmpX ];
1260 const long nAlpha3 = pLine1[ nTmpX ];
1261 const long n0 = MAP( nAlpha0, nAlpha1, nTmpFX );
1262 const long n1 = MAP( nAlpha2, nAlpha3, nTmpFX );
1263
1264 *pLineW++ = MAP( n0, n1, nTmpFY );
1265 }
1266 }
1267 }
1268 else
1269 {
1270 BitmapColor aAlphaValue( 0 );
1271
1272 for( nY = nStartY, nYDst = 0L; nY <= nEndY; nY++, nYDst++ )
1273 {
1274 nTmpY = pMapIY[ nY ], nTmpFY = pMapFY[ nY ];
1275
1276 for( nX = nStartX, nXDst = 0L; nX <= nEndX; nX++ )
1277 {
1278 nTmpX = pMapIX[ nX ]; nTmpFX = pMapFX[ nX ];
1279
1280 long nAlpha0 = pAcc->GetPixel( nTmpY, nTmpX ).GetIndex();
1281 long nAlpha1 = pAcc->GetPixel( nTmpY, ++nTmpX ).GetIndex();
1282 const long n0 = MAP( nAlpha0, nAlpha1, nTmpFX );
1283
1284 nAlpha1 = pAcc->GetPixel( ++nTmpY, nTmpX ).GetIndex();
1285 nAlpha0 = pAcc->GetPixel( nTmpY--, --nTmpX ).GetIndex();
1286 const long n1 = MAP( nAlpha0, nAlpha1, nTmpFX );
1287
1288 aAlphaValue.SetIndex( MAP( n0, n1, nTmpFY ) );
1289 pWAcc->SetPixel( nYDst, nXDst++, aAlphaValue );
1290 }
1291 }
1292 }
1293
1294 aOutAlpha.ReleaseAccess( pWAcc );
1295 bRet = sal_True;
1296 }
1297
1298 aAlpha.ReleaseAccess( pAcc );
1299
1300 if( bRet )
1301 rOutBmpEx = BitmapEx( aOutBmp, aOutAlpha );
1302 }
1303 }
1304 else
1305 {
1306 DBG_ASSERT( rBmpEx.GetMask().GetSizePixel() == rBmpEx.GetSizePixel(),
1307 "GraphicManager::ImplCreateScaled(): mask size inconsistent" );
1308
1309 Bitmap aMsk( rBmpEx.GetMask() );
1310 Bitmap aOutMsk;
1311
1312 pAcc = aMsk.AcquireReadAccess();
1313
1314 if( pAcc )
1315 {
1316 // #i40115# Use the same palette for destination
1317 // bitmap. Otherwise, we'd have to color-map even the
1318 // case below, when both masks are one bit deep.
1319 if( pAcc->HasPalette() )
1320 aOutMsk = Bitmap( Size( nDstW, nDstH ),
1321 1,
1322 &pAcc->GetPalette() );
1323 else
1324 aOutMsk = Bitmap( Size( nDstW, nDstH ), 1 );
1325
1326 pWAcc = aOutMsk.AcquireWriteAccess();
1327
1328 if( pWAcc )
1329 {
1330 long* pMapLX = new long[ nDstW ];
1331 long* pMapLY = new long[ nDstH ];
1332
1333 // create new horizontal mapping table
1334 for( nX = 0UL, nTmpX = nStartX; nX < nDstW; nTmpX++ )
1335 pMapLX[ nX++ ] = FRound( (double) pMapIX[ nTmpX ] + pMapFX[ nTmpX ] / 1048576. );
1336
1337 // create new vertical mapping table
1338 for( nY = 0UL, nTmpY = nStartY; nY < nDstH; nTmpY++ )
1339 pMapLY[ nY++ ] = FRound( (double) pMapIY[ nTmpY ] + pMapFY[ nTmpY ] / 1048576. );
1340
1341 // do normal scaling
1342 if( pAcc->GetScanlineFormat() == BMP_FORMAT_1BIT_MSB_PAL &&
1343 pWAcc->GetScanlineFormat() == BMP_FORMAT_1BIT_MSB_PAL )
1344 {
1345 // optimized
1346 for( nY = 0; nY < nDstH; nY++ )
1347 {
1348 Scanline pSrc = pAcc->GetScanline( pMapLY[ nY ] );
1349 Scanline pDst = pWAcc->GetScanline( nY );
1350
1351 for( nX = 0L; nX < nDstW; nX++ )
1352 {
1353 const long nSrcX = pMapLX[ nX ];
1354
1355 if( pSrc[ nSrcX >> 3 ] & ( 1 << ( 7 - ( nSrcX & 7 ) ) ) )
1356 pDst[ nX >> 3 ] |= 1 << ( 7 - ( nX & 7 ) );
1357 else
1358 pDst[ nX >> 3 ] &= ~( 1 << ( 7 - ( nX & 7 ) ) );
1359 }
1360 }
1361 }
1362 else
1363 {
1364 const BitmapColor aB( pAcc->GetBestMatchingColor( Color( COL_BLACK ) ) );
1365 const BitmapColor aWB( pWAcc->GetBestMatchingColor( Color( COL_BLACK ) ) );
1366 const BitmapColor aWW( pWAcc->GetBestMatchingColor( Color( COL_WHITE ) ) );
1367
1368 if( pAcc->HasPalette() )
1369 {
1370 for( nY = 0L; nY < nDstH; nY++ )
1371 {
1372 for( nX = 0L; nX < nDstW; nX++ )
1373 {
1374 if( pAcc->GetPaletteColor( pAcc->GetPixelIndex( pMapLY[ nY ], pMapLX[ nX ] ) ) == aB )
1375 pWAcc->SetPixel( nY, nX, aWB );
1376 else
1377 pWAcc->SetPixel( nY, nX, aWW );
1378 }
1379 }
1380 }
1381 else
1382 {
1383 for( nY = 0L; nY < nDstH; nY++ )
1384 {
1385 for( nX = 0L; nX < nDstW; nX++ )
1386 {
1387 if( pAcc->GetPixel( pMapLY[ nY ], pMapLX[ nX ] ) == aB )
1388 pWAcc->SetPixel( nY, nX, aWB );
1389 else
1390 pWAcc->SetPixel( nY, nX, aWW );
1391 }
1392 }
1393 }
1394 }
1395
1396 delete[] pMapLX;
1397 delete[] pMapLY;
1398 aOutMsk.ReleaseAccess( pWAcc );
1399 bRet = sal_True;
1400 }
1401
1402 aMsk.ReleaseAccess( pAcc );
1403
1404 if( bRet )
1405 rOutBmpEx = BitmapEx( aOutBmp, aOutMsk );
1406 }
1407 }
1408
1409 if( !bRet )
1410 rOutBmpEx = aOutBmp;
1411 }
1412 else
1413 rOutBmpEx = aOutBmp;
1414
1415 return bRet;
1416 }
1417
1418 // -----------------------------------------------------------------------------
1419
ImplCreateRotatedScaled(const BitmapEx & rBmpEx,sal_uInt16 nRot10,const Size &,const Size & rUnrotatedSzPix,long * pMapIX,long * pMapFX,long * pMapIY,long * pMapFY,long nStartX,long nEndX,long nStartY,long nEndY,BitmapEx & rOutBmpEx)1420 sal_Bool GraphicManager::ImplCreateRotatedScaled( const BitmapEx& rBmpEx,
1421 sal_uInt16 nRot10, const Size& /*rOutSzPix*/, const Size& rUnrotatedSzPix,
1422 long* pMapIX, long* pMapFX, long* pMapIY, long* pMapFY,
1423 long nStartX, long nEndX, long nStartY, long nEndY,
1424 BitmapEx& rOutBmpEx )
1425 {
1426 Point aPt;
1427 Bitmap aBmp( rBmpEx.GetBitmap() );
1428 Bitmap aOutBmp;
1429 BitmapReadAccess* pAcc = aBmp.AcquireReadAccess();
1430 BitmapWriteAccess* pWAcc;
1431 Polygon aPoly( Rectangle( aPt, rUnrotatedSzPix ) ); aPoly.Rotate( Point(), nRot10 );
1432 Rectangle aNewBound( aPoly.GetBoundRect() );
1433 const double fCosAngle = cos( nRot10 * F_PI1800 ), fSinAngle = sin( nRot10 * F_PI1800 );
1434 double fTmp;
1435 const long nDstW = nEndX - nStartX + 1L;
1436 const long nDstH = nEndY - nStartY + 1L;
1437 const long nUnRotW = rUnrotatedSzPix.Width();
1438 const long nUnRotH = rUnrotatedSzPix.Height();
1439 long* pCosX = new long[ nDstW ];
1440 long* pSinX = new long[ nDstW ];
1441 long* pCosY = new long[ nDstH ];
1442 long* pSinY = new long[ nDstH ];
1443 long nX, nY, nTmpX, nTmpY, nTmpFX, nTmpFY, nUnRotX, nUnRotY, nSinY, nCosY;
1444 sal_uInt8 cR0, cG0, cB0, cR1, cG1, cB1;
1445 sal_Bool bRet = sal_False;
1446
1447 // create horizontal mapping table
1448 for( nX = 0L, nTmpX = aNewBound.Left() + nStartX; nX < nDstW; nX++ )
1449 {
1450 pCosX[ nX ] = FRound( fCosAngle * ( fTmp = nTmpX++ << 8 ) );
1451 pSinX[ nX ] = FRound( fSinAngle * fTmp );
1452 }
1453
1454 // create vertical mapping table
1455 for( nY = 0L, nTmpY = aNewBound.Top() + nStartY; nY < nDstH; nY++ )
1456 {
1457 pCosY[ nY ] = FRound( fCosAngle * ( fTmp = nTmpY++ << 8 ) );
1458 pSinY[ nY ] = FRound( fSinAngle * fTmp );
1459 }
1460
1461 if( pAcc )
1462 {
1463 aOutBmp = Bitmap( Size( nDstW, nDstH ), 24 );
1464 pWAcc = aOutBmp.AcquireWriteAccess();
1465
1466 if( pWAcc )
1467 {
1468 BitmapColor aColRes;
1469
1470 if( pAcc->HasPalette() )
1471 {
1472 for( nY = 0; nY < nDstH; nY++ )
1473 {
1474 nSinY = pSinY[ nY ];
1475 nCosY = pCosY[ nY ];
1476
1477 for( nX = 0; nX < nDstW; nX++ )
1478 {
1479 nUnRotX = ( pCosX[ nX ] - nSinY ) >> 8;
1480 nUnRotY = ( pSinX[ nX ] + nCosY ) >> 8;
1481
1482 if( ( nUnRotX >= 0L ) && ( nUnRotX < nUnRotW ) &&
1483 ( nUnRotY >= 0L ) && ( nUnRotY < nUnRotH ) )
1484 {
1485 nTmpX = pMapIX[ nUnRotX ]; nTmpFX = pMapFX[ nUnRotX ];
1486 nTmpY = pMapIY[ nUnRotY ], nTmpFY = pMapFY[ nUnRotY ];
1487
1488 const BitmapColor& rCol0 = pAcc->GetPaletteColor( pAcc->GetPixelIndex( nTmpY, nTmpX ) );
1489 const BitmapColor& rCol1 = pAcc->GetPaletteColor( pAcc->GetPixelIndex( nTmpY, ++nTmpX ) );
1490 cR0 = MAP( rCol0.GetRed(), rCol1.GetRed(), nTmpFX );
1491 cG0 = MAP( rCol0.GetGreen(), rCol1.GetGreen(), nTmpFX );
1492 cB0 = MAP( rCol0.GetBlue(), rCol1.GetBlue(), nTmpFX );
1493
1494 const BitmapColor& rCol3 = pAcc->GetPaletteColor( pAcc->GetPixelIndex( ++nTmpY, nTmpX ) );
1495 const BitmapColor& rCol2 = pAcc->GetPaletteColor( pAcc->GetPixelIndex( nTmpY, --nTmpX ) );
1496 cR1 = MAP( rCol2.GetRed(), rCol3.GetRed(), nTmpFX );
1497 cG1 = MAP( rCol2.GetGreen(), rCol3.GetGreen(), nTmpFX );
1498 cB1 = MAP( rCol2.GetBlue(), rCol3.GetBlue(), nTmpFX );
1499
1500 aColRes.SetRed( MAP( cR0, cR1, nTmpFY ) );
1501 aColRes.SetGreen( MAP( cG0, cG1, nTmpFY ) );
1502 aColRes.SetBlue( MAP( cB0, cB1, nTmpFY ) );
1503 pWAcc->SetPixel( nY, nX, aColRes );
1504 }
1505 }
1506 }
1507 }
1508 else
1509 {
1510 BitmapColor aCol0, aCol1;
1511
1512 for( nY = 0; nY < nDstH; nY++ )
1513 {
1514 nSinY = pSinY[ nY ];
1515 nCosY = pCosY[ nY ];
1516
1517 for( nX = 0; nX < nDstW; nX++ )
1518 {
1519 nUnRotX = ( pCosX[ nX ] - nSinY ) >> 8;
1520 nUnRotY = ( pSinX[ nX ] + nCosY ) >> 8;
1521
1522 if( ( nUnRotX >= 0L ) && ( nUnRotX < nUnRotW ) &&
1523 ( nUnRotY >= 0L ) && ( nUnRotY < nUnRotH ) )
1524 {
1525 nTmpX = pMapIX[ nUnRotX ]; nTmpFX = pMapFX[ nUnRotX ];
1526 nTmpY = pMapIY[ nUnRotY ], nTmpFY = pMapFY[ nUnRotY ];
1527
1528 aCol0 = pAcc->GetPixel( nTmpY, nTmpX );
1529 aCol1 = pAcc->GetPixel( nTmpY, ++nTmpX );
1530 cR0 = MAP( aCol0.GetRed(), aCol1.GetRed(), nTmpFX );
1531 cG0 = MAP( aCol0.GetGreen(), aCol1.GetGreen(), nTmpFX );
1532 cB0 = MAP( aCol0.GetBlue(), aCol1.GetBlue(), nTmpFX );
1533
1534 aCol1 = pAcc->GetPixel( ++nTmpY, nTmpX );
1535 aCol0 = pAcc->GetPixel( nTmpY, --nTmpX );
1536 cR1 = MAP( aCol0.GetRed(), aCol1.GetRed(), nTmpFX );
1537 cG1 = MAP( aCol0.GetGreen(), aCol1.GetGreen(), nTmpFX );
1538 cB1 = MAP( aCol0.GetBlue(), aCol1.GetBlue(), nTmpFX );
1539
1540 aColRes.SetRed( MAP( cR0, cR1, nTmpFY ) );
1541 aColRes.SetGreen( MAP( cG0, cG1, nTmpFY ) );
1542 aColRes.SetBlue( MAP( cB0, cB1, nTmpFY ) );
1543 pWAcc->SetPixel( nY, nX, aColRes );
1544 }
1545 }
1546 }
1547 }
1548
1549 aOutBmp.ReleaseAccess( pWAcc );
1550 bRet = sal_True;
1551 }
1552
1553 aBmp.ReleaseAccess( pAcc );
1554 }
1555
1556 // mask processing
1557 if( bRet && ( rBmpEx.IsTransparent() || ( nRot10 != 900 && nRot10 != 1800 && nRot10 != 2700 ) ) )
1558 {
1559 bRet = sal_False;
1560
1561 if( rBmpEx.IsAlpha() )
1562 {
1563 AlphaMask aAlpha( rBmpEx.GetAlpha() );
1564 AlphaMask aOutAlpha;
1565
1566 pAcc = aAlpha.AcquireReadAccess();
1567
1568 if( pAcc )
1569 {
1570 aOutAlpha = AlphaMask( Size( nDstW, nDstH ) );
1571 pWAcc = aOutAlpha.AcquireWriteAccess();
1572
1573 if( pWAcc )
1574 {
1575 if( pAcc->GetScanlineFormat() == BMP_FORMAT_8BIT_PAL &&
1576 pWAcc->GetScanlineFormat() == BMP_FORMAT_8BIT_PAL )
1577 {
1578 Scanline pLine0, pLine1, pLineW;
1579
1580 for( nY = 0; nY < nDstH; nY++ )
1581 {
1582 nSinY = pSinY[ nY ], nCosY = pCosY[ nY ];
1583 pLineW = pWAcc->GetScanline( nY );
1584
1585 for( nX = 0; nX < nDstW; nX++ )
1586 {
1587 nUnRotX = ( pCosX[ nX ] - nSinY ) >> 8;
1588 nUnRotY = ( pSinX[ nX ] + nCosY ) >> 8;
1589
1590 if( ( nUnRotX >= 0L ) && ( nUnRotX < nUnRotW ) &&
1591 ( nUnRotY >= 0L ) && ( nUnRotY < nUnRotH ) )
1592 {
1593 nTmpX = pMapIX[ nUnRotX ], nTmpFX = pMapFX[ nUnRotX ];
1594 nTmpY = pMapIY[ nUnRotY ], nTmpFY = pMapFY[ nUnRotY ];
1595
1596 pLine0 = pAcc->GetScanline( nTmpY++ );
1597 pLine1 = pAcc->GetScanline( nTmpY );
1598
1599 const long nAlpha0 = pLine0[ nTmpX ];
1600 const long nAlpha2 = pLine1[ nTmpX++ ];
1601 const long nAlpha1 = pLine0[ nTmpX ];
1602 const long nAlpha3 = pLine1[ nTmpX ];
1603 const long n0 = MAP( nAlpha0, nAlpha1, nTmpFX );
1604 const long n1 = MAP( nAlpha2, nAlpha3, nTmpFX );
1605
1606 *pLineW++ = MAP( n0, n1, nTmpFY );
1607 }
1608 else
1609 *pLineW++ = 255;
1610 }
1611 }
1612 }
1613 else
1614 {
1615 const BitmapColor aTrans( pWAcc->GetBestMatchingColor( Color( COL_WHITE ) ) );
1616 BitmapColor aAlphaVal( 0 );
1617
1618 for( nY = 0; nY < nDstH; nY++ )
1619 {
1620 nSinY = pSinY[ nY ], nCosY = pCosY[ nY ];
1621
1622 for( nX = 0; nX < nDstW; nX++ )
1623 {
1624 nUnRotX = ( pCosX[ nX ] - nSinY ) >> 8;
1625 nUnRotY = ( pSinX[ nX ] + nCosY ) >> 8;
1626
1627 if( ( nUnRotX >= 0L ) && ( nUnRotX < nUnRotW ) &&
1628 ( nUnRotY >= 0L ) && ( nUnRotY < nUnRotH ) )
1629 {
1630 nTmpX = pMapIX[ nUnRotX ]; nTmpFX = pMapFX[ nUnRotX ];
1631 nTmpY = pMapIY[ nUnRotY ], nTmpFY = pMapFY[ nUnRotY ];
1632
1633 const long nAlpha0 = pAcc->GetPixel( nTmpY, nTmpX ).GetIndex();
1634 const long nAlpha1 = pAcc->GetPixel( nTmpY, ++nTmpX ).GetIndex();
1635 const long nAlpha3 = pAcc->GetPixel( ++nTmpY, nTmpX ).GetIndex();
1636 const long nAlpha2 = pAcc->GetPixel( nTmpY, --nTmpX ).GetIndex();
1637 const long n0 = MAP( nAlpha0, nAlpha1, nTmpFX );
1638 const long n1 = MAP( nAlpha2, nAlpha3, nTmpFX );
1639
1640 aAlphaVal.SetIndex( MAP( n0, n1, nTmpFY ) );
1641 pWAcc->SetPixel( nY, nX, aAlphaVal );
1642 }
1643 else
1644 pWAcc->SetPixel( nY, nX, aTrans );
1645 }
1646 }
1647 }
1648
1649 aOutAlpha.ReleaseAccess( pWAcc );
1650 bRet = sal_True;
1651 }
1652
1653 aAlpha.ReleaseAccess( pAcc );
1654 }
1655
1656 if( bRet )
1657 rOutBmpEx = BitmapEx( aOutBmp, aOutAlpha );
1658 }
1659 else
1660 {
1661 Bitmap aOutMsk( Size( nDstW, nDstH ), 1 );
1662 pWAcc = aOutMsk.AcquireWriteAccess();
1663
1664 if( pWAcc )
1665 {
1666 Bitmap aMsk( rBmpEx.GetMask() );
1667 const BitmapColor aB( pWAcc->GetBestMatchingColor( Color( COL_BLACK ) ) );
1668 const BitmapColor aW( pWAcc->GetBestMatchingColor( Color( COL_WHITE ) ) );
1669 BitmapReadAccess* pMAcc = NULL;
1670
1671 if( !aMsk || ( ( pMAcc = aMsk.AcquireReadAccess() ) != NULL ) )
1672 {
1673 long* pMapLX = new long[ nUnRotW ];
1674 long* pMapLY = new long[ nUnRotH ];
1675 BitmapColor aTestB;
1676
1677 if( pMAcc )
1678 aTestB = pMAcc->GetBestMatchingColor( Color( COL_BLACK ) );
1679
1680 // create new horizontal mapping table
1681 for( nX = 0UL; nX < nUnRotW; nX++ )
1682 pMapLX[ nX ] = FRound( (double) pMapIX[ nX ] + pMapFX[ nX ] / 1048576. );
1683
1684 // create new vertical mapping table
1685 for( nY = 0UL; nY < nUnRotH; nY++ )
1686 pMapLY[ nY ] = FRound( (double) pMapIY[ nY ] + pMapFY[ nY ] / 1048576. );
1687
1688 // do mask rotation
1689 for( nY = 0; nY < nDstH; nY++ )
1690 {
1691 nSinY = pSinY[ nY ];
1692 nCosY = pCosY[ nY ];
1693
1694 for( nX = 0; nX < nDstW; nX++ )
1695 {
1696 nUnRotX = ( pCosX[ nX ] - nSinY ) >> 8;
1697 nUnRotY = ( pSinX[ nX ] + nCosY ) >> 8;
1698
1699 if( ( nUnRotX >= 0L ) && ( nUnRotX < nUnRotW ) &&
1700 ( nUnRotY >= 0L ) && ( nUnRotY < nUnRotH ) )
1701 {
1702 if( pMAcc )
1703 {
1704 if( pMAcc->GetPixel( pMapLY[ nUnRotY ], pMapLX[ nUnRotX ] ) == aTestB )
1705 pWAcc->SetPixel( nY, nX, aB );
1706 else
1707 pWAcc->SetPixel( nY, nX, aW );
1708 }
1709 else
1710 pWAcc->SetPixel( nY, nX, aB );
1711 }
1712 else
1713 pWAcc->SetPixel( nY, nX, aW );
1714 }
1715 }
1716
1717 delete[] pMapLX;
1718 delete[] pMapLY;
1719
1720 if( pMAcc )
1721 aMsk.ReleaseAccess( pMAcc );
1722
1723 bRet = sal_True;
1724 }
1725
1726 aOutMsk.ReleaseAccess( pWAcc );
1727 }
1728
1729 if( bRet )
1730 rOutBmpEx = BitmapEx( aOutBmp, aOutMsk );
1731 }
1732
1733 if( !bRet )
1734 rOutBmpEx = aOutBmp;
1735 }
1736 else
1737 rOutBmpEx = aOutBmp;
1738
1739 delete[] pSinX;
1740 delete[] pCosX;
1741 delete[] pSinY;
1742 delete[] pCosY;
1743
1744 return bRet;
1745 }
1746
1747 // -----------------------------------------------------------------------------
1748
ImplAdjust(BitmapEx & rBmpEx,const GraphicAttr & rAttr,sal_uLong nAdjustmentFlags)1749 void GraphicManager::ImplAdjust( BitmapEx& rBmpEx, const GraphicAttr& rAttr, sal_uLong nAdjustmentFlags )
1750 {
1751 GraphicAttr aAttr( rAttr );
1752
1753 if( ( nAdjustmentFlags & ADJUSTMENT_DRAWMODE ) && aAttr.IsSpecialDrawMode() )
1754 {
1755 switch( aAttr.GetDrawMode() )
1756 {
1757 case( GRAPHICDRAWMODE_MONO ):
1758 rBmpEx.Convert( BMP_CONVERSION_1BIT_THRESHOLD );
1759 break;
1760
1761 case( GRAPHICDRAWMODE_GREYS ):
1762 rBmpEx.Convert( BMP_CONVERSION_8BIT_GREYS );
1763 break;
1764
1765 case( GRAPHICDRAWMODE_WATERMARK ):
1766 {
1767 aAttr.SetLuminance( aAttr.GetLuminance() + WATERMARK_LUM_OFFSET );
1768 aAttr.SetContrast( aAttr.GetContrast() + WATERMARK_CON_OFFSET );
1769 }
1770 break;
1771
1772 default:
1773 break;
1774 }
1775 }
1776
1777 if( ( nAdjustmentFlags & ADJUSTMENT_COLORS ) && aAttr.IsAdjusted() )
1778 {
1779 rBmpEx.Adjust( aAttr.GetLuminance(), aAttr.GetContrast(),
1780 aAttr.GetChannelR(), aAttr.GetChannelG(), aAttr.GetChannelB(),
1781 aAttr.GetGamma(), aAttr.IsInvert() );
1782 }
1783
1784 if( ( nAdjustmentFlags & ADJUSTMENT_MIRROR ) && aAttr.IsMirrored() )
1785 {
1786 rBmpEx.Mirror( aAttr.GetMirrorFlags() );
1787 }
1788
1789 if( ( nAdjustmentFlags & ADJUSTMENT_ROTATE ) && aAttr.IsRotated() )
1790 {
1791 rBmpEx.Rotate( aAttr.GetRotation(), Color( COL_TRANSPARENT ) );
1792 }
1793
1794 if( ( nAdjustmentFlags & ADJUSTMENT_TRANSPARENCY ) && aAttr.IsTransparent() )
1795 {
1796 AlphaMask aAlpha;
1797 sal_uInt8 cTrans = aAttr.GetTransparency();
1798
1799 if( !rBmpEx.IsTransparent() )
1800 aAlpha = AlphaMask( rBmpEx.GetSizePixel(), &cTrans );
1801 else if( !rBmpEx.IsAlpha() )
1802 {
1803 aAlpha = rBmpEx.GetMask();
1804 aAlpha.Replace( 0, cTrans );
1805 }
1806 else
1807 {
1808 aAlpha = rBmpEx.GetAlpha();
1809 BitmapWriteAccess* pA = aAlpha.AcquireWriteAccess();
1810
1811 if( pA )
1812 {
1813 sal_uLong nTrans = cTrans, nNewTrans;
1814 const long nWidth = pA->Width(), nHeight = pA->Height();
1815
1816 if( pA->GetScanlineFormat() == BMP_FORMAT_8BIT_PAL )
1817 {
1818 for( long nY = 0; nY < nHeight; nY++ )
1819 {
1820 Scanline pAScan = pA->GetScanline( nY );
1821
1822 for( long nX = 0; nX < nWidth; nX++ )
1823 {
1824 nNewTrans = nTrans + *pAScan;
1825 *pAScan++ = (sal_uInt8) ( ( nNewTrans & 0xffffff00 ) ? 255 : nNewTrans );
1826 }
1827 }
1828 }
1829 else
1830 {
1831 BitmapColor aAlphaValue( 0 );
1832
1833 for( long nY = 0; nY < nHeight; nY++ )
1834 {
1835 for( long nX = 0; nX < nWidth; nX++ )
1836 {
1837 nNewTrans = nTrans + pA->GetPixel( nY, nX ).GetIndex();
1838 aAlphaValue.SetIndex( (sal_uInt8) ( ( nNewTrans & 0xffffff00 ) ? 255 : nNewTrans ) );
1839 pA->SetPixel( nY, nX, aAlphaValue );
1840 }
1841 }
1842 }
1843
1844 aAlpha.ReleaseAccess( pA );
1845 }
1846 }
1847
1848 rBmpEx = BitmapEx( rBmpEx.GetBitmap(), aAlpha );
1849 }
1850 }
1851
1852 // -----------------------------------------------------------------------------
1853
ImplAdjust(GDIMetaFile & rMtf,const GraphicAttr & rAttr,sal_uLong nAdjustmentFlags)1854 void GraphicManager::ImplAdjust( GDIMetaFile& rMtf, const GraphicAttr& rAttr, sal_uLong nAdjustmentFlags )
1855 {
1856 GraphicAttr aAttr( rAttr );
1857
1858 if( ( nAdjustmentFlags & ADJUSTMENT_DRAWMODE ) && aAttr.IsSpecialDrawMode() )
1859 {
1860 switch( aAttr.GetDrawMode() )
1861 {
1862 case( GRAPHICDRAWMODE_MONO ):
1863 rMtf.Convert( MTF_CONVERSION_1BIT_THRESHOLD );
1864 break;
1865
1866 case( GRAPHICDRAWMODE_GREYS ):
1867 rMtf.Convert( MTF_CONVERSION_8BIT_GREYS );
1868 break;
1869
1870 case( GRAPHICDRAWMODE_WATERMARK ):
1871 {
1872 aAttr.SetLuminance( aAttr.GetLuminance() + WATERMARK_LUM_OFFSET );
1873 aAttr.SetContrast( aAttr.GetContrast() + WATERMARK_CON_OFFSET );
1874 }
1875 break;
1876
1877 default:
1878 break;
1879 }
1880 }
1881
1882 if( ( nAdjustmentFlags & ADJUSTMENT_COLORS ) && aAttr.IsAdjusted() )
1883 {
1884 rMtf.Adjust( aAttr.GetLuminance(), aAttr.GetContrast(),
1885 aAttr.GetChannelR(), aAttr.GetChannelG(), aAttr.GetChannelB(),
1886 aAttr.GetGamma(), aAttr.IsInvert() );
1887 }
1888
1889 if( ( nAdjustmentFlags & ADJUSTMENT_MIRROR ) && aAttr.IsMirrored() )
1890 {
1891 rMtf.Mirror( aAttr.GetMirrorFlags() );
1892 }
1893
1894 if( ( nAdjustmentFlags & ADJUSTMENT_ROTATE ) && aAttr.IsRotated() )
1895 {
1896 rMtf.Rotate( aAttr.GetRotation() );
1897 }
1898
1899 if( ( nAdjustmentFlags & ADJUSTMENT_TRANSPARENCY ) && aAttr.IsTransparent() )
1900 {
1901 DBG_WARNING( "Missing implementation: Mtf-Transparency" );
1902 }
1903 }
1904
1905 // -----------------------------------------------------------------------------
1906
ImplAdjust(Animation & rAnimation,const GraphicAttr & rAttr,sal_uLong nAdjustmentFlags)1907 void GraphicManager::ImplAdjust( Animation& rAnimation, const GraphicAttr& rAttr, sal_uLong nAdjustmentFlags )
1908 {
1909 GraphicAttr aAttr( rAttr );
1910
1911 if( ( nAdjustmentFlags & ADJUSTMENT_DRAWMODE ) && aAttr.IsSpecialDrawMode() )
1912 {
1913 switch( aAttr.GetDrawMode() )
1914 {
1915 case( GRAPHICDRAWMODE_MONO ):
1916 rAnimation.Convert( BMP_CONVERSION_1BIT_THRESHOLD );
1917 break;
1918
1919 case( GRAPHICDRAWMODE_GREYS ):
1920 rAnimation.Convert( BMP_CONVERSION_8BIT_GREYS );
1921 break;
1922
1923 case( GRAPHICDRAWMODE_WATERMARK ):
1924 {
1925 aAttr.SetLuminance( aAttr.GetLuminance() + WATERMARK_LUM_OFFSET );
1926 aAttr.SetContrast( aAttr.GetContrast() + WATERMARK_CON_OFFSET );
1927 }
1928 break;
1929
1930 default:
1931 break;
1932 }
1933 }
1934
1935 if( ( nAdjustmentFlags & ADJUSTMENT_COLORS ) && aAttr.IsAdjusted() )
1936 {
1937 rAnimation.Adjust( aAttr.GetLuminance(), aAttr.GetContrast(),
1938 aAttr.GetChannelR(), aAttr.GetChannelG(), aAttr.GetChannelB(),
1939 aAttr.GetGamma(), aAttr.IsInvert() );
1940 }
1941
1942 if( ( nAdjustmentFlags & ADJUSTMENT_MIRROR ) && aAttr.IsMirrored() )
1943 {
1944 rAnimation.Mirror( aAttr.GetMirrorFlags() );
1945 }
1946
1947 if( ( nAdjustmentFlags & ADJUSTMENT_ROTATE ) && aAttr.IsRotated() )
1948 {
1949 DBG_ERROR( "Missing implementation: Animation-Rotation" );
1950 }
1951
1952 if( ( nAdjustmentFlags & ADJUSTMENT_TRANSPARENCY ) && aAttr.IsTransparent() )
1953 {
1954 DBG_ERROR( "Missing implementation: Animation-Transparency" );
1955 }
1956 }
1957
1958 // -----------------------------------------------------------------------------
1959
ImplDraw(OutputDevice * pOut,const Point & rPt,const Size & rSz,const GDIMetaFile & rMtf,const GraphicAttr & rAttr)1960 void GraphicManager::ImplDraw( OutputDevice* pOut, const Point& rPt, const Size& rSz,
1961 const GDIMetaFile& rMtf, const GraphicAttr& rAttr )
1962 {
1963 sal_uInt16 nRot10 = rAttr.GetRotation() % 3600;
1964 Point aOutPt( rPt );
1965 Size aOutSz( rSz );
1966
1967 if( nRot10 )
1968 {
1969 Polygon aPoly( Rectangle( aOutPt, aOutSz ) );
1970
1971 aPoly.Rotate( aOutPt, nRot10 );
1972 const Rectangle aRotBoundRect( aPoly.GetBoundRect() );
1973 aOutPt = aRotBoundRect.TopLeft();
1974 aOutSz = aRotBoundRect.GetSize();
1975 }
1976
1977 pOut->Push( PUSH_CLIPREGION );
1978 pOut->IntersectClipRegion( Rectangle( aOutPt, aOutSz ) );
1979
1980 ( (GDIMetaFile&) rMtf ).WindStart();
1981 ( (GDIMetaFile&) rMtf ).Play( pOut, aOutPt, aOutSz );
1982 ( (GDIMetaFile&) rMtf ).WindStart();
1983
1984 pOut->Pop();
1985 }
1986
1987 // -----------------------------------------------------------------------------
1988
1989 struct ImplTileInfo
1990 {
ImplTileInfoImplTileInfo1991 ImplTileInfo() : aTileTopLeft(), aNextTileTopLeft(), aTileSizePixel(), nTilesEmptyX(0), nTilesEmptyY(0) {}
1992
1993 Point aTileTopLeft; // top, left position of the rendered tile
1994 Point aNextTileTopLeft; // top, left position for next recursion
1995 // level's tile
1996 Size aTileSizePixel; // size of the generated tile (might
1997 // differ from
1998 // aNextTileTopLeft-aTileTopLeft, because
1999 // this is nExponent*prevTileSize. The
2000 // generated tile is always nExponent
2001 // times the previous tile, such that it
2002 // can be used in the next stage. The
2003 // required area coverage is often
2004 // less. The extraneous area covered is
2005 // later overwritten by the next stage)
2006 int nTilesEmptyX; // number of original tiles empty right of
2007 // this tile. This counts from
2008 // aNextTileTopLeft, i.e. the additional
2009 // area covered by aTileSizePixel is not
2010 // considered here. This is for
2011 // unification purposes, as the iterative
2012 // calculation of the next level's empty
2013 // tiles has to be based on this value.
2014 int nTilesEmptyY; // as above, for Y
2015 };
2016
2017
ImplRenderTempTile(VirtualDevice & rVDev,int nExponent,int nNumTilesX,int nNumTilesY,const Size & rTileSizePixel,const GraphicAttr * pAttr,sal_uLong nFlags)2018 bool GraphicObject::ImplRenderTempTile( VirtualDevice& rVDev, int nExponent,
2019 int nNumTilesX, int nNumTilesY,
2020 const Size& rTileSizePixel,
2021 const GraphicAttr* pAttr, sal_uLong nFlags )
2022 {
2023 if( nExponent <= 1 )
2024 return false;
2025
2026 // determine MSB factor
2027 int nMSBFactor( 1 );
2028 while( nNumTilesX / nMSBFactor != 0 ||
2029 nNumTilesY / nMSBFactor != 0 )
2030 {
2031 nMSBFactor *= nExponent;
2032 }
2033
2034 // one less
2035 nMSBFactor /= nExponent;
2036
2037 ImplTileInfo aTileInfo;
2038
2039 // #105229# Switch off mapping (converting to logic and back to
2040 // pixel might cause roundoff errors)
2041 sal_Bool bOldMap( rVDev.IsMapModeEnabled() );
2042 rVDev.EnableMapMode( sal_False );
2043
2044 bool bRet( ImplRenderTileRecursive( rVDev, nExponent, nMSBFactor, nNumTilesX, nNumTilesY,
2045 nNumTilesX, nNumTilesY, rTileSizePixel, pAttr, nFlags, aTileInfo ) );
2046
2047 rVDev.EnableMapMode( bOldMap );
2048
2049 return bRet;
2050 }
2051
2052 // -----------------------------------------------------------------------------
2053
2054 // define for debug drawings
2055 //#define DBG_TEST
2056
2057 // see header comment. this works similar to base conversion of a
2058 // number, i.e. if the exponent is 10, then the number for every tile
2059 // size is given by the decimal place of the corresponding decimal
2060 // representation.
ImplRenderTileRecursive(VirtualDevice & rVDev,int nExponent,int nMSBFactor,int nNumOrigTilesX,int nNumOrigTilesY,int nRemainderTilesX,int nRemainderTilesY,const Size & rTileSizePixel,const GraphicAttr * pAttr,sal_uLong nFlags,ImplTileInfo & rTileInfo)2061 bool GraphicObject::ImplRenderTileRecursive( VirtualDevice& rVDev, int nExponent, int nMSBFactor,
2062 int nNumOrigTilesX, int nNumOrigTilesY,
2063 int nRemainderTilesX, int nRemainderTilesY,
2064 const Size& rTileSizePixel, const GraphicAttr* pAttr,
2065 sal_uLong nFlags, ImplTileInfo& rTileInfo )
2066 {
2067 // gets loaded with our tile bitmap
2068 GraphicObject aTmpGraphic;
2069
2070 // stores a flag that renders the zero'th tile position
2071 // (i.e. (0,0)+rCurrPos) only if we're at the bottom of the
2072 // recursion stack. All other position already have that tile
2073 // rendered, because the lower levels painted their generated tile
2074 // there.
2075 bool bNoFirstTileDraw( false );
2076
2077 // what's left when we're done with our tile size
2078 const int nNewRemainderX( nRemainderTilesX % nMSBFactor );
2079 const int nNewRemainderY( nRemainderTilesY % nMSBFactor );
2080
2081 // gets filled out from the recursive call with info of what's
2082 // been generated
2083 ImplTileInfo aTileInfo;
2084
2085 // current output position while drawing
2086 Point aCurrPos;
2087 int nX, nY;
2088
2089 // check for recursion's end condition: LSB place reached?
2090 if( nMSBFactor == 1 )
2091 {
2092 aTmpGraphic = *this;
2093
2094 // set initial tile size -> orig size
2095 aTileInfo.aTileSizePixel = rTileSizePixel;
2096 aTileInfo.nTilesEmptyX = nNumOrigTilesX;
2097 aTileInfo.nTilesEmptyY = nNumOrigTilesY;
2098 }
2099 else if( ImplRenderTileRecursive( rVDev, nExponent, nMSBFactor/nExponent,
2100 nNumOrigTilesX, nNumOrigTilesY,
2101 nNewRemainderX, nNewRemainderY,
2102 rTileSizePixel, pAttr, nFlags, aTileInfo ) )
2103 {
2104 // extract generated tile -> see comment on the first loop below
2105 BitmapEx aTileBitmap( rVDev.GetBitmap( aTileInfo.aTileTopLeft, aTileInfo.aTileSizePixel ) );
2106
2107 aTmpGraphic = GraphicObject( aTileBitmap );
2108
2109 // fill stripes left over from upstream levels:
2110 //
2111 // x0000
2112 // 0
2113 // 0
2114 // 0
2115 // 0
2116 //
2117 // where x denotes the place filled by our recursive predecessors
2118
2119 // check whether we have to fill stripes here. Although not
2120 // obvious, there is one case where we can skip this step: if
2121 // the previous recursion level (the one who filled our
2122 // aTileInfo) had zero area to fill, then there are no white
2123 // stripes left, naturally. This happens if the digit
2124 // associated to that level has a zero, and can be checked via
2125 // aTileTopLeft==aNextTileTopLeft.
2126 if( aTileInfo.aTileTopLeft != aTileInfo.aNextTileTopLeft )
2127 {
2128 // now fill one row from aTileInfo.aNextTileTopLeft.X() all
2129 // the way to the right
2130 aCurrPos.X() = aTileInfo.aNextTileTopLeft.X();
2131 aCurrPos.Y() = aTileInfo.aTileTopLeft.Y();
2132 for( nX=0; nX < aTileInfo.nTilesEmptyX; nX += nMSBFactor )
2133 {
2134 if( !aTmpGraphic.Draw( &rVDev, aCurrPos, aTileInfo.aTileSizePixel, pAttr, nFlags ) )
2135 return false;
2136
2137 aCurrPos.X() += aTileInfo.aTileSizePixel.Width();
2138 }
2139
2140 #ifdef DBG_TEST
2141 // rVDev.SetFillColor( COL_WHITE );
2142 rVDev.SetFillColor();
2143 rVDev.SetLineColor( Color( 255 * nExponent / nMSBFactor, 255 - 255 * nExponent / nMSBFactor, 128 - 255 * nExponent / nMSBFactor ) );
2144 rVDev.DrawEllipse( Rectangle(aTileInfo.aNextTileTopLeft.X(), aTileInfo.aTileTopLeft.Y(),
2145 aTileInfo.aNextTileTopLeft.X() - 1 + (aTileInfo.nTilesEmptyX/nMSBFactor)*aTileInfo.aTileSizePixel.Width(),
2146 aTileInfo.aTileTopLeft.Y() + aTileInfo.aTileSizePixel.Height() - 1) );
2147 #endif
2148
2149 // now fill one column from aTileInfo.aNextTileTopLeft.Y() all
2150 // the way to the bottom
2151 aCurrPos.X() = aTileInfo.aTileTopLeft.X();
2152 aCurrPos.Y() = aTileInfo.aNextTileTopLeft.Y();
2153 for( nY=0; nY < aTileInfo.nTilesEmptyY; nY += nMSBFactor )
2154 {
2155 if( !aTmpGraphic.Draw( &rVDev, aCurrPos, aTileInfo.aTileSizePixel, pAttr, nFlags ) )
2156 return false;
2157
2158 aCurrPos.Y() += aTileInfo.aTileSizePixel.Height();
2159 }
2160
2161 #ifdef DBG_TEST
2162 rVDev.DrawEllipse( Rectangle(aTileInfo.aTileTopLeft.X(), aTileInfo.aNextTileTopLeft.Y(),
2163 aTileInfo.aTileTopLeft.X() + aTileInfo.aTileSizePixel.Width() - 1,
2164 aTileInfo.aNextTileTopLeft.Y() - 1 + (aTileInfo.nTilesEmptyY/nMSBFactor)*aTileInfo.aTileSizePixel.Height()) );
2165 #endif
2166 }
2167 else
2168 {
2169 // Thought that aTileInfo.aNextTileTopLeft tile has always
2170 // been drawn already, but that's wrong: typically,
2171 // _parts_ of that tile have been drawn, since the
2172 // previous level generated the tile there. But when
2173 // aTileInfo.aNextTileTopLeft!=aTileInfo.aTileTopLeft, the
2174 // difference between these two values is missing in the
2175 // lower right corner of this first tile. So, can do that
2176 // only here.
2177 bNoFirstTileDraw = true;
2178 }
2179 }
2180 else
2181 {
2182 return false;
2183 }
2184
2185 // calc number of original tiles in our drawing area without
2186 // remainder
2187 nRemainderTilesX -= nNewRemainderX;
2188 nRemainderTilesY -= nNewRemainderY;
2189
2190 // fill tile info for calling method
2191 rTileInfo.aTileTopLeft = aTileInfo.aNextTileTopLeft;
2192 rTileInfo.aNextTileTopLeft = Point( rTileInfo.aTileTopLeft.X() + rTileSizePixel.Width()*nRemainderTilesX,
2193 rTileInfo.aTileTopLeft.Y() + rTileSizePixel.Height()*nRemainderTilesY );
2194 rTileInfo.aTileSizePixel = Size( rTileSizePixel.Width()*nMSBFactor*nExponent,
2195 rTileSizePixel.Height()*nMSBFactor*nExponent );
2196 rTileInfo.nTilesEmptyX = aTileInfo.nTilesEmptyX - nRemainderTilesX;
2197 rTileInfo.nTilesEmptyY = aTileInfo.nTilesEmptyY - nRemainderTilesY;
2198
2199 // init output position
2200 aCurrPos = aTileInfo.aNextTileTopLeft;
2201
2202 // fill our drawing area. Fill possibly more, to create the next
2203 // bigger tile size -> see bitmap extraction above. This does no
2204 // harm, since everything right or below our actual area is
2205 // overdrawn by our caller. Just in case we're in the last level,
2206 // we don't draw beyond the right or bottom border.
2207 for( nY=0; nY < aTileInfo.nTilesEmptyY && nY < nExponent*nMSBFactor; nY += nMSBFactor )
2208 {
2209 aCurrPos.X() = aTileInfo.aNextTileTopLeft.X();
2210
2211 for( nX=0; nX < aTileInfo.nTilesEmptyX && nX < nExponent*nMSBFactor; nX += nMSBFactor )
2212 {
2213 if( bNoFirstTileDraw )
2214 bNoFirstTileDraw = false; // don't draw first tile position
2215 else if( !aTmpGraphic.Draw( &rVDev, aCurrPos, aTileInfo.aTileSizePixel, pAttr, nFlags ) )
2216 return false;
2217
2218 aCurrPos.X() += aTileInfo.aTileSizePixel.Width();
2219 }
2220
2221 aCurrPos.Y() += aTileInfo.aTileSizePixel.Height();
2222 }
2223
2224 #ifdef DBG_TEST
2225 // rVDev.SetFillColor( COL_WHITE );
2226 rVDev.SetFillColor();
2227 rVDev.SetLineColor( Color( 255 * nExponent / nMSBFactor, 255 - 255 * nExponent / nMSBFactor, 128 - 255 * nExponent / nMSBFactor ) );
2228 rVDev.DrawRect( Rectangle((rTileInfo.aTileTopLeft.X())*rTileSizePixel.Width(),
2229 (rTileInfo.aTileTopLeft.Y())*rTileSizePixel.Height(),
2230 (rTileInfo.aNextTileTopLeft.X())*rTileSizePixel.Width()-1,
2231 (rTileInfo.aNextTileTopLeft.Y())*rTileSizePixel.Height()-1) );
2232 #endif
2233
2234 return true;
2235 }
2236
2237 // -----------------------------------------------------------------------------
2238
ImplDrawTiled(OutputDevice * pOut,const Rectangle & rArea,const Size & rSizePixel,const Size & rOffset,const GraphicAttr * pAttr,sal_uLong nFlags,int nTileCacheSize1D)2239 bool GraphicObject::ImplDrawTiled( OutputDevice* pOut, const Rectangle& rArea, const Size& rSizePixel,
2240 const Size& rOffset, const GraphicAttr* pAttr, sal_uLong nFlags, int nTileCacheSize1D )
2241 {
2242 // how many tiles to generate per recursion step
2243 enum{ SubdivisionExponent=2 };
2244
2245 const MapMode aOutMapMode( pOut->GetMapMode() );
2246 const MapMode aMapMode( aOutMapMode.GetMapUnit(), Point(), aOutMapMode.GetScaleX(), aOutMapMode.GetScaleY() );
2247 bool bRet( false );
2248
2249 // #i42643# Casting to Int64, to avoid integer overflow for
2250 // huge-DPI output devices
2251 if( GetGraphic().GetType() == GRAPHIC_BITMAP &&
2252 static_cast<sal_Int64>(rSizePixel.Width()) * rSizePixel.Height() <
2253 static_cast<sal_Int64>(nTileCacheSize1D)*nTileCacheSize1D )
2254 {
2255 // First combine very small bitmaps into a larger tile
2256 // ===================================================
2257
2258 VirtualDevice aVDev;
2259 const int nNumTilesInCacheX( (nTileCacheSize1D + rSizePixel.Width()-1) / rSizePixel.Width() );
2260 const int nNumTilesInCacheY( (nTileCacheSize1D + rSizePixel.Height()-1) / rSizePixel.Height() );
2261
2262 aVDev.SetOutputSizePixel( Size( nNumTilesInCacheX*rSizePixel.Width(),
2263 nNumTilesInCacheY*rSizePixel.Height() ) );
2264 aVDev.SetMapMode( aMapMode );
2265
2266 // draw bitmap content
2267 if( ImplRenderTempTile( aVDev, SubdivisionExponent, nNumTilesInCacheX,
2268 nNumTilesInCacheY, rSizePixel, pAttr, nFlags ) )
2269 {
2270 BitmapEx aTileBitmap( aVDev.GetBitmap( Point(0,0), aVDev.GetOutputSize() ) );
2271
2272 // draw alpha content, if any
2273 if( IsTransparent() )
2274 {
2275 GraphicObject aAlphaGraphic;
2276
2277 if( GetGraphic().IsAlpha() )
2278 aAlphaGraphic.SetGraphic( GetGraphic().GetBitmapEx().GetAlpha().GetBitmap() );
2279 else
2280 aAlphaGraphic.SetGraphic( GetGraphic().GetBitmapEx().GetMask() );
2281
2282 if( aAlphaGraphic.ImplRenderTempTile( aVDev, SubdivisionExponent, nNumTilesInCacheX,
2283 nNumTilesInCacheY, rSizePixel, pAttr, nFlags ) )
2284 {
2285 // Combine bitmap and alpha/mask
2286 if( GetGraphic().IsAlpha() )
2287 aTileBitmap = BitmapEx( aTileBitmap.GetBitmap(),
2288 AlphaMask( aVDev.GetBitmap( Point(0,0), aVDev.GetOutputSize() ) ) );
2289 else
2290 aTileBitmap = BitmapEx( aTileBitmap.GetBitmap(),
2291 aVDev.GetBitmap( Point(0,0), aVDev.GetOutputSize() ).CreateMask( Color(COL_WHITE) ) );
2292 }
2293 }
2294
2295 // paint generated tile
2296 GraphicObject aTmpGraphic( aTileBitmap );
2297 bRet = aTmpGraphic.ImplDrawTiled( pOut, rArea,
2298 aTileBitmap.GetSizePixel(),
2299 rOffset, pAttr, nFlags, nTileCacheSize1D );
2300 }
2301 }
2302 else
2303 {
2304 const Size aOutOffset( pOut->LogicToPixel( rOffset, aOutMapMode ) );
2305 const Rectangle aOutArea( pOut->LogicToPixel( rArea, aOutMapMode ) );
2306
2307 // number of invisible (because out-of-area) tiles
2308 int nInvisibleTilesX;
2309 int nInvisibleTilesY;
2310
2311 // round towards -infty for negative offset
2312 if( aOutOffset.Width() < 0 )
2313 nInvisibleTilesX = (aOutOffset.Width() - rSizePixel.Width() + 1) / rSizePixel.Width();
2314 else
2315 nInvisibleTilesX = aOutOffset.Width() / rSizePixel.Width();
2316
2317 // round towards -infty for negative offset
2318 if( aOutOffset.Height() < 0 )
2319 nInvisibleTilesY = (aOutOffset.Height() - rSizePixel.Height() + 1) / rSizePixel.Height();
2320 else
2321 nInvisibleTilesY = aOutOffset.Height() / rSizePixel.Height();
2322
2323 // origin from where to 'virtually' start drawing in pixel
2324 const Point aOutOrigin( pOut->LogicToPixel( Point( rArea.Left() - rOffset.Width(),
2325 rArea.Top() - rOffset.Height() ) ) );
2326 // position in pixel from where to really start output
2327 const Point aOutStart( aOutOrigin.X() + nInvisibleTilesX*rSizePixel.Width(),
2328 aOutOrigin.Y() + nInvisibleTilesY*rSizePixel.Height() );
2329
2330 pOut->Push( PUSH_CLIPREGION );
2331 pOut->IntersectClipRegion( rArea );
2332
2333 // Paint all tiles
2334 // ===============
2335
2336 bRet = ImplDrawTiled( *pOut, aOutStart,
2337 (aOutArea.GetWidth() + aOutArea.Left() - aOutStart.X() + rSizePixel.Width() - 1) / rSizePixel.Width(),
2338 (aOutArea.GetHeight() + aOutArea.Top() - aOutStart.Y() + rSizePixel.Height() - 1) / rSizePixel.Height(),
2339 rSizePixel, pAttr, nFlags );
2340
2341 pOut->Pop();
2342 }
2343
2344 return bRet;
2345 }
2346
2347 // -----------------------------------------------------------------------------
2348
ImplDrawTiled(OutputDevice & rOut,const Point & rPosPixel,int nNumTilesX,int nNumTilesY,const Size & rTileSizePixel,const GraphicAttr * pAttr,sal_uLong nFlags)2349 bool GraphicObject::ImplDrawTiled( OutputDevice& rOut, const Point& rPosPixel,
2350 int nNumTilesX, int nNumTilesY,
2351 const Size& rTileSizePixel, const GraphicAttr* pAttr, sal_uLong nFlags )
2352 {
2353 Point aCurrPos( rPosPixel );
2354 Size aTileSizeLogic( rOut.PixelToLogic( rTileSizePixel ) );
2355 int nX, nY;
2356
2357 // #107607# Use logical coordinates for metafile playing, too
2358 bool bDrawInPixel( rOut.GetConnectMetaFile() == NULL && GRAPHIC_BITMAP == GetType() );
2359 sal_Bool bRet( sal_False );
2360
2361 // #105229# Switch off mapping (converting to logic and back to
2362 // pixel might cause roundoff errors)
2363 sal_Bool bOldMap( rOut.IsMapModeEnabled() );
2364
2365 if( bDrawInPixel )
2366 rOut.EnableMapMode( sal_False );
2367
2368 for( nY=0; nY < nNumTilesY; ++nY )
2369 {
2370 aCurrPos.X() = rPosPixel.X();
2371
2372 for( nX=0; nX < nNumTilesX; ++nX )
2373 {
2374 // #105229# work with pixel coordinates here, mapping is disabled!
2375 // #104004# don't disable mapping for metafile recordings
2376 // #108412# don't quit the loop if one draw fails
2377
2378 // update return value. This method should return true, if
2379 // at least one of the looped Draws succeeded.
2380 bRet |= Draw( &rOut,
2381 bDrawInPixel ? aCurrPos : rOut.PixelToLogic( aCurrPos ),
2382 bDrawInPixel ? rTileSizePixel : aTileSizeLogic,
2383 pAttr, nFlags );
2384
2385 aCurrPos.X() += rTileSizePixel.Width();
2386 }
2387
2388 aCurrPos.Y() += rTileSizePixel.Height();
2389 }
2390
2391 if( bDrawInPixel )
2392 rOut.EnableMapMode( bOldMap );
2393
2394 return bRet;
2395 }
2396
2397 // -----------------------------------------------------------------------------
2398
ImplTransformBitmap(BitmapEx & rBmpEx,const GraphicAttr & rAttr,const Size & rCropLeftTop,const Size & rCropRightBottom,const Rectangle & rCropRect,const Size & rDstSize,sal_Bool bEnlarge) const2399 void GraphicObject::ImplTransformBitmap( BitmapEx& rBmpEx,
2400 const GraphicAttr& rAttr,
2401 const Size& rCropLeftTop,
2402 const Size& rCropRightBottom,
2403 const Rectangle& rCropRect,
2404 const Size& rDstSize,
2405 sal_Bool bEnlarge ) const
2406 {
2407 // #107947# Extracted from svdograf.cxx
2408
2409 // #104115# Crop the bitmap
2410 if( rAttr.IsCropped() )
2411 {
2412 rBmpEx.Crop( rCropRect );
2413
2414 // #104115# Negative crop sizes mean: enlarge bitmap and pad
2415 if( bEnlarge && (
2416 rCropLeftTop.Width() < 0 ||
2417 rCropLeftTop.Height() < 0 ||
2418 rCropRightBottom.Width() < 0 ||
2419 rCropRightBottom.Height() < 0 ) )
2420 {
2421 Size aBmpSize( rBmpEx.GetSizePixel() );
2422 sal_Int32 nPadLeft( rCropLeftTop.Width() < 0 ? -rCropLeftTop.Width() : 0 );
2423 sal_Int32 nPadTop( rCropLeftTop.Height() < 0 ? -rCropLeftTop.Height() : 0 );
2424 sal_Int32 nPadTotalWidth( aBmpSize.Width() + nPadLeft + (rCropRightBottom.Width() < 0 ? -rCropRightBottom.Width() : 0) );
2425 sal_Int32 nPadTotalHeight( aBmpSize.Height() + nPadTop + (rCropRightBottom.Height() < 0 ? -rCropRightBottom.Height() : 0) );
2426
2427 BitmapEx aBmpEx2;
2428
2429 if( rBmpEx.IsTransparent() )
2430 {
2431 if( rBmpEx.IsAlpha() )
2432 aBmpEx2 = BitmapEx( rBmpEx.GetBitmap(), rBmpEx.GetAlpha() );
2433 else
2434 aBmpEx2 = BitmapEx( rBmpEx.GetBitmap(), rBmpEx.GetMask() );
2435 }
2436 else
2437 {
2438 // #104115# Generate mask bitmap and init to zero
2439 Bitmap aMask( aBmpSize, 1 );
2440 aMask.Erase( Color(0,0,0) );
2441
2442 // #104115# Always generate transparent bitmap, we need the border transparent
2443 aBmpEx2 = BitmapEx( rBmpEx.GetBitmap(), aMask );
2444
2445 // #104115# Add opaque mask to source bitmap, otherwise the destination remains transparent
2446 rBmpEx = aBmpEx2;
2447 }
2448
2449 aBmpEx2.SetSizePixel( Size(nPadTotalWidth, nPadTotalHeight) );
2450 aBmpEx2.Erase( Color(0xFF,0,0,0) );
2451 aBmpEx2.CopyPixel( Rectangle( Point(nPadLeft, nPadTop), aBmpSize ), Rectangle( Point(0, 0), aBmpSize ), &rBmpEx );
2452 rBmpEx = aBmpEx2;
2453 }
2454 }
2455
2456 const Size aSizePixel( rBmpEx.GetSizePixel() );
2457
2458 if( rAttr.GetRotation() != 0 && !IsAnimated() )
2459 {
2460 if( aSizePixel.Width() && aSizePixel.Height() && rDstSize.Width() && rDstSize.Height() )
2461 {
2462 double fSrcWH = (double) aSizePixel.Width() / aSizePixel.Height();
2463 double fDstWH = (double) rDstSize.Width() / rDstSize.Height();
2464 double fScaleX = 1.0, fScaleY = 1.0;
2465
2466 // always choose scaling to shrink bitmap
2467 if( fSrcWH < fDstWH )
2468 fScaleY = aSizePixel.Width() / ( fDstWH * aSizePixel.Height() );
2469 else
2470 fScaleX = fDstWH * aSizePixel.Height() / aSizePixel.Width();
2471
2472 rBmpEx.Scale( fScaleX, fScaleY );
2473 }
2474 }
2475 }
2476