1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_sd.hxx"
30 
31 #include "PreviewRenderer.hxx"
32 
33 #include "DrawDocShell.hxx"
34 #include "drawdoc.hxx"
35 #include "drawview.hxx"
36 #include "sdpage.hxx"
37 #include "ViewShell.hxx"
38 #include <vcl/virdev.hxx>
39 #include <svx/svdpagv.hxx>
40 #include <svx/svdoutl.hxx>
41 #include <editeng/eeitem.hxx>
42 #include <editeng/editstat.hxx>
43 #include <tools/link.hxx>
44 #include <vcl/svapp.hxx>
45 #include <tools/diagnose_ex.h>
46 #include <svx/sdr/contact/viewobjectcontact.hxx>
47 #include <svx/sdr/contact/viewcontact.hxx>
48 
49 using namespace ::com::sun::star;
50 using namespace ::com::sun::star::uno;
51 
52 
53 namespace sd {
54 
55 const int PreviewRenderer::snSubstitutionTextSize = 11;
56 const int PreviewRenderer::snFrameWidth = 1;
57 
58 namespace {
59     /** This incarnation of the ViewObjectContactRedirector filters away all
60         PageObj objects, unconditionally.
61     */
62     class ViewRedirector : public ::sdr::contact::ViewObjectContactRedirector
63     {
64     public:
65         ViewRedirector (void);
66         virtual ~ViewRedirector (void);
67         virtual drawinglayer::primitive2d::Primitive2DSequence createRedirectedPrimitive2DSequence(
68             const sdr::contact::ViewObjectContact& rOriginal,
69                 const sdr::contact::DisplayInfo& rDisplayInfo);
70     };
71 }
72 
73 
74 
75 
76 //===== PreviewRenderer =======================================================
77 
78 PreviewRenderer::PreviewRenderer (
79     OutputDevice* pTemplate,
80     const bool bHasFrame)
81     : mpPreviewDevice (new VirtualDevice()),
82       mpView(NULL),
83       mpDocShellOfView(NULL),
84       mnWidthOfView(0),
85       maFrameColor (svtools::ColorConfig().GetColorValue(svtools::DOCBOUNDARIES).nColor),
86       mbHasFrame(bHasFrame)
87 {
88     if (pTemplate != NULL)
89     {
90         mpPreviewDevice->SetDigitLanguage (pTemplate->GetDigitLanguage());
91         mpPreviewDevice->SetBackground(pTemplate->GetBackground());
92     }
93     else
94     {
95         mpPreviewDevice->SetBackground(Wallpaper(
96             Application::GetSettings().GetStyleSettings().GetWindowColor()));
97     }
98 }
99 
100 
101 
102 
103 PreviewRenderer::~PreviewRenderer (void)
104 {
105     if (mpDocShellOfView != NULL)
106         EndListening (*mpDocShellOfView);
107 }
108 
109 
110 
111 
112 Image PreviewRenderer::RenderPage (
113     const SdPage* pPage,
114     const sal_Int32 nWidth,
115     const String& rSubstitutionText,
116     const bool bObeyHighContrastMode,
117     const bool bDisplayPresentationObjects)
118 {
119     if (pPage != NULL)
120     {
121         const Size aPageModelSize (pPage->GetSize());
122         const double nAspectRatio (
123             double(aPageModelSize.Width()) / double(aPageModelSize.Height()));
124         const sal_Int32 nFrameWidth (mbHasFrame ? snFrameWidth : 0);
125         const sal_Int32 nHeight (sal::static_int_cast<sal_Int32>(
126             (nWidth - 2*nFrameWidth) / nAspectRatio + 2*nFrameWidth + 0.5));
127         return RenderPage (
128             pPage,
129             Size(nWidth,nHeight),
130             rSubstitutionText,
131             bObeyHighContrastMode,
132             bDisplayPresentationObjects);
133     }
134     else
135         return Image();
136 }
137 
138 
139 
140 
141 Image PreviewRenderer::RenderPage (
142     const SdPage* pPage,
143     Size aPixelSize,
144     const String& rSubstitutionText,
145     const bool bObeyHighContrastMode,
146     const bool bDisplayPresentationObjects)
147 {
148     Image aPreview;
149 
150     if (pPage != NULL)
151     {
152         try
153         {
154             if (Initialize(pPage, aPixelSize, bObeyHighContrastMode))
155             {
156                 PaintPage(pPage, bDisplayPresentationObjects);
157                 PaintSubstitutionText(rSubstitutionText);
158                 PaintFrame();
159 
160                 Size aSize (mpPreviewDevice->GetOutputSizePixel());
161                 aPreview = mpPreviewDevice->GetBitmap (
162                     mpPreviewDevice->PixelToLogic(Point(0,0)),
163                     mpPreviewDevice->PixelToLogic(aSize));
164 
165                 Cleanup();
166             }
167         }
168         catch (const com::sun::star::uno::Exception&)
169         {
170             DBG_UNHANDLED_EXCEPTION();
171         }
172     }
173 
174     return aPreview;
175 }
176 
177 
178 
179 
180 Image PreviewRenderer::RenderSubstitution (
181     const Size& rPreviewPixelSize,
182     const String& rSubstitutionText)
183 {
184     Image aPreview;
185 
186     try
187     {
188         // Set size.
189         mpPreviewDevice->SetOutputSizePixel(rPreviewPixelSize);
190 
191         // Adjust contrast mode.
192         const bool bUseContrast (
193             Application::GetSettings().GetStyleSettings().GetHighContrastMode());
194         mpPreviewDevice->SetDrawMode (bUseContrast
195             ? ViewShell::OUTPUT_DRAWMODE_CONTRAST
196             : ViewShell::OUTPUT_DRAWMODE_COLOR);
197 
198         // Set a map mode that makes a typical substitution text completely
199         // visible.
200         MapMode aMapMode (mpPreviewDevice->GetMapMode());
201         aMapMode.SetMapUnit(MAP_100TH_MM);
202         const double nFinalScale (25.0 * rPreviewPixelSize.Width() / 28000.0);
203         aMapMode.SetScaleX(nFinalScale);
204         aMapMode.SetScaleY(nFinalScale);
205         const sal_Int32 nFrameWidth (mbHasFrame ? snFrameWidth : 0);
206         aMapMode.SetOrigin(mpPreviewDevice->PixelToLogic(
207             Point(nFrameWidth,nFrameWidth),aMapMode));
208         mpPreviewDevice->SetMapMode (aMapMode);
209 
210         // Clear the background.
211         const Rectangle aPaintRectangle (
212             Point(0,0),
213             mpPreviewDevice->GetOutputSizePixel());
214         mpPreviewDevice->EnableMapMode(sal_False);
215         mpPreviewDevice->SetLineColor();
216         svtools::ColorConfig aColorConfig;
217         mpPreviewDevice->SetFillColor(aColorConfig.GetColorValue(svtools::DOCCOLOR).nColor);
218         mpPreviewDevice->DrawRect (aPaintRectangle);
219         mpPreviewDevice->EnableMapMode(sal_True);
220 
221         // Paint substitution text and a frame around it.
222         PaintSubstitutionText (rSubstitutionText);
223         PaintFrame();
224 
225         const Size aSize (mpPreviewDevice->GetOutputSizePixel());
226         aPreview = mpPreviewDevice->GetBitmap (
227             mpPreviewDevice->PixelToLogic(Point(0,0)),
228             mpPreviewDevice->PixelToLogic(aSize));
229     }
230     catch (const com::sun::star::uno::Exception&)
231     {
232         DBG_UNHANDLED_EXCEPTION();
233     }
234 
235     return aPreview;
236 }
237 
238 
239 
240 
241 bool PreviewRenderer::Initialize (
242     const SdPage* pPage,
243     const Size& rPixelSize,
244     const bool bObeyHighContrastMode)
245 {
246     bool bSuccess = false;
247     do
248     {
249         if (pPage == NULL)
250             break;
251 
252         SdrModel* pModel = pPage->GetModel();
253         if (pModel == NULL)
254             break;
255 
256         SetupOutputSize(*pPage, rPixelSize);
257 
258         SdDrawDocument* pDocument
259             = static_cast<SdDrawDocument*>(pPage->GetModel());
260         DrawDocShell* pDocShell = pDocument->GetDocSh();
261 
262         // Create view
263         ProvideView (pDocShell);
264         if (mpView.get() == NULL)
265             break;
266 
267         // Adjust contrast mode.
268         bool bUseContrast (bObeyHighContrastMode
269             && Application::GetSettings().GetStyleSettings().GetHighContrastMode());
270         mpPreviewDevice->SetDrawMode (bUseContrast
271             ? ViewShell::OUTPUT_DRAWMODE_CONTRAST
272             : ViewShell::OUTPUT_DRAWMODE_COLOR);
273         mpPreviewDevice->SetSettings(Application::GetSettings());
274 
275         // Tell the view to show the given page.
276         SdPage* pNonConstPage = const_cast<SdPage*>(pPage);
277         if (pPage->IsMasterPage())
278 		{
279 			mpView->ShowSdrPage(mpView->GetModel()->GetMasterPage(pPage->GetPageNum()));
280 		}
281         else
282 		{
283             mpView->ShowSdrPage(pNonConstPage);
284 		}
285 
286         // Make sure that a page view exists.
287         SdrPageView* pPageView = mpView->GetSdrPageView();
288         if (pPageView == NULL)
289             break;
290         // Set background color of page view and outliner.
291         svtools::ColorConfig aColorConfig;
292         const Color aPageBackgroundColor(pPage->GetPageBackgroundColor(pPageView));
293         pPageView->SetApplicationBackgroundColor(aPageBackgroundColor);
294         SdrOutliner& rOutliner (pDocument->GetDrawOutliner(NULL));
295         rOutliner.SetBackgroundColor(aPageBackgroundColor);
296         rOutliner.SetDefaultLanguage(pDocument->GetLanguage(EE_CHAR_LANGUAGE));
297         mpView->SetApplicationBackgroundColor(
298             Color(aColorConfig.GetColorValue(svtools::APPBACKGROUND).nColor));
299         mpPreviewDevice->SetBackground(Wallpaper(aPageBackgroundColor));
300         mpPreviewDevice->Erase();
301 
302         bSuccess = true;
303     }
304     while (false);
305 
306     return bSuccess;
307 }
308 
309 
310 
311 
312 void PreviewRenderer::Cleanup (void)
313 {
314     mpView->HideSdrPage();
315 }
316 
317 
318 
319 
320 void PreviewRenderer::PaintPage (
321     const SdPage* pPage,
322     const bool bDisplayPresentationObjects)
323 {
324     // Paint the page.
325     Rectangle aPaintRectangle (Point(0,0), pPage->GetSize());
326     Region aRegion (aPaintRectangle);
327 
328     // Turn off online spelling and redlining.
329     SdrOutliner* pOutliner = NULL;
330     sal_uLong nSavedControlWord (0);
331     if (mpDocShellOfView!=NULL && mpDocShellOfView->GetDoc()!=NULL)
332     {
333         pOutliner = &mpDocShellOfView->GetDoc()->GetDrawOutliner();
334         nSavedControlWord = pOutliner->GetControlWord();
335         pOutliner->SetControlWord((nSavedControlWord & ~EE_CNTRL_ONLINESPELLING));
336     }
337 
338     // Use a special redirector to prevent PresObj shapes from being painted.
339     boost::scoped_ptr<ViewRedirector> pRedirector;
340     if ( ! bDisplayPresentationObjects)
341         pRedirector.reset(new ViewRedirector());
342 
343     try
344     {
345         mpView->CompleteRedraw(mpPreviewDevice.get(), aRegion, pRedirector.get());
346     }
347     catch (const ::com::sun::star::uno::Exception&)
348     {
349         DBG_UNHANDLED_EXCEPTION();
350     }
351 
352     // Restore the previous online spelling and redlining states.
353     if (pOutliner != NULL)
354         pOutliner->SetControlWord(nSavedControlWord);
355 }
356 
357 
358 
359 
360 void PreviewRenderer::PaintSubstitutionText (const String& rSubstitutionText)
361 {
362     if (rSubstitutionText.Len() > 0)
363     {
364         // Set the font size.
365         const Font& rOriginalFont (mpPreviewDevice->GetFont());
366         Font aFont (mpPreviewDevice->GetSettings().GetStyleSettings().GetAppFont());
367         sal_Int32 nHeight (mpPreviewDevice->PixelToLogic(Size(0,snSubstitutionTextSize)).Height());
368         aFont.SetHeight(nHeight);
369         mpPreviewDevice->SetFont (aFont);
370 
371         // Paint the substitution text.
372         Rectangle aTextBox (
373             Point(0,0),
374             mpPreviewDevice->PixelToLogic(
375                 mpPreviewDevice->GetOutputSizePixel()));
376         sal_uInt16 nTextStyle =
377             TEXT_DRAW_CENTER
378             | TEXT_DRAW_VCENTER
379             | TEXT_DRAW_MULTILINE
380             | TEXT_DRAW_WORDBREAK;
381         mpPreviewDevice->DrawText (aTextBox, rSubstitutionText, nTextStyle);
382 
383         // Restore the font.
384         mpPreviewDevice->SetFont (rOriginalFont);
385     }
386 }
387 
388 
389 
390 
391 void PreviewRenderer::PaintFrame (void)
392 {
393     if (mbHasFrame)
394     {
395         // Paint a frame arround the preview.
396         Rectangle aPaintRectangle (
397             Point(0,0),
398             mpPreviewDevice->GetOutputSizePixel());
399         mpPreviewDevice->EnableMapMode(sal_False);
400         mpPreviewDevice->SetLineColor(maFrameColor);
401         mpPreviewDevice->SetFillColor();
402         mpPreviewDevice->DrawRect(aPaintRectangle);
403         mpPreviewDevice->EnableMapMode(sal_True);
404      }
405 }
406 
407 
408 
409 
410 void PreviewRenderer::SetupOutputSize (
411     const SdPage& rPage,
412     const Size& rFramePixelSize)
413 {
414     // First set the map mode to some arbitrary scale that is numerically
415     // stable.
416     MapMode aMapMode (mpPreviewDevice->GetMapMode());
417 	aMapMode.SetMapUnit(MAP_PIXEL);
418 
419     // Adapt it to the desired width.
420     const Size aPageModelSize (rPage.GetSize());
421     if (aPageModelSize.Width()>0 || aPageModelSize.Height()>0)
422     {
423         const sal_Int32 nFrameWidth (mbHasFrame ? snFrameWidth : 0);
424         aMapMode.SetScaleX(
425             Fraction(rFramePixelSize.Width()-2*nFrameWidth-1, aPageModelSize.Width()));
426         aMapMode.SetScaleY(
427             Fraction(rFramePixelSize.Height()-2*nFrameWidth-1, aPageModelSize.Height()));
428         aMapMode.SetOrigin(mpPreviewDevice->PixelToLogic(Point(nFrameWidth,nFrameWidth),aMapMode));
429     }
430     else
431     {
432         // We should never get here.
433         OSL_ASSERT(false);
434         aMapMode.SetScaleX(1.0);
435         aMapMode.SetScaleY(1.0);
436     }
437     mpPreviewDevice->SetMapMode (aMapMode);
438     mpPreviewDevice->SetOutputSizePixel(rFramePixelSize);
439 }
440 
441 
442 
443 
444 void PreviewRenderer::ProvideView (DrawDocShell* pDocShell)
445 {
446     if (pDocShell != mpDocShellOfView)
447     {
448         // Destroy the view that is connected to the current doc shell.
449         mpView.reset (NULL);
450 
451         // Switch our attention, i.e. listening for DYING events, to
452         // the new doc shell.
453         if (mpDocShellOfView != NULL)
454             EndListening (*mpDocShellOfView);
455         mpDocShellOfView = pDocShell;
456         if (mpDocShellOfView != NULL)
457             StartListening (*mpDocShellOfView);
458     }
459     if (mpView.get() == NULL)
460     {
461         mpView.reset (new DrawView (pDocShell, mpPreviewDevice.get(), NULL));
462     }
463 	mpView->SetPreviewRenderer(true);
464 #if 1
465     mpView->SetPageVisible(false);
466 	mpView->SetPageBorderVisible(true);
467 	mpView->SetBordVisible(false);
468 #else
469     // This works in the slide sorter but prevents the master page
470     // background being painted in the list of current master pages in the
471     // task manager.
472     mpView->SetPagePaintingAllowed(false);
473 #endif
474 }
475 
476 
477 
478 
479 Image PreviewRenderer::ScaleBitmap (
480     const BitmapEx& rBitmapEx,
481     int nWidth)
482 {
483     Image aPreview;
484 
485     do
486     {
487         // Adjust contrast mode.
488         bool bUseContrast = Application::GetSettings().GetStyleSettings().
489             GetHighContrastMode();
490         mpPreviewDevice->SetDrawMode (bUseContrast
491             ? ViewShell::OUTPUT_DRAWMODE_CONTRAST
492             : ViewShell::OUTPUT_DRAWMODE_COLOR);
493 
494         // Set output size.
495         Size aSize (rBitmapEx.GetSizePixel());
496         if (aSize.Width() <= 0)
497             break;
498         Size aFrameSize (
499             nWidth,
500             (long)((nWidth*1.0 * aSize.Height()) / aSize.Width() + 0.5));
501         Size aPreviewSize (aFrameSize.Width()-2,aFrameSize.Height()-2);
502         MapMode aMapMode (mpPreviewDevice->GetMapMode());
503         aMapMode.SetMapUnit(MAP_PIXEL);
504         aMapMode.SetOrigin (Point());
505         aMapMode.SetScaleX (1.0);
506         aMapMode.SetScaleY (1.0);
507         mpPreviewDevice->SetMapMode (aMapMode);
508         mpPreviewDevice->SetOutputSize (aFrameSize);
509 
510         // Paint a frame arround the preview.
511         mpPreviewDevice->SetLineColor (maFrameColor);
512         mpPreviewDevice->SetFillColor ();
513         mpPreviewDevice->DrawRect (Rectangle(Point(0,0), aFrameSize));
514 
515         // Paint the bitmap scaled to the desired width.
516         BitmapEx aScaledBitmap (rBitmapEx.GetBitmap());
517         aScaledBitmap.Scale (aPreviewSize, BMP_SCALE_INTERPOLATE);
518         mpPreviewDevice->DrawBitmap (
519             Point(1,1),
520             aPreviewSize,
521             aScaledBitmap.GetBitmap());
522 
523         // Get the resulting bitmap.
524         aPreview = mpPreviewDevice->GetBitmap (Point(0,0), aFrameSize);
525     }
526     while (false);
527 
528     return aPreview;
529 }
530 
531 
532 
533 
534 void PreviewRenderer::Notify(SfxBroadcaster&, const SfxHint& rHint)
535 {
536 	if (rHint.IsA(TYPE(SfxSimpleHint))
537         && mpDocShellOfView != NULL)
538     {
539         const SfxSimpleHint* pSimpleHint = PTR_CAST(SfxSimpleHint, &rHint);
540         if (pSimpleHint != NULL
541             && pSimpleHint->GetId() == SFX_HINT_DYING)
542 		{
543             // The doc shell is dying.  Our view uses its item pool and
544             // has to be destroyed as well.  The next call to
545             // ProvideView will create a new one (for another
546             // doc shell, of course.)
547             mpView.reset (NULL);
548             mpDocShellOfView = NULL;
549         }
550     }
551 }
552 
553 
554 
555 
556 //===== ViewRedirector ========================================================
557 
558 namespace {
559 
560 ViewRedirector::ViewRedirector (void)
561 {
562 }
563 
564 
565 
566 
567 ViewRedirector::~ViewRedirector (void)
568 {
569 }
570 
571 
572 
573 
574 drawinglayer::primitive2d::Primitive2DSequence ViewRedirector::createRedirectedPrimitive2DSequence(
575 	const sdr::contact::ViewObjectContact& rOriginal,
576 	const sdr::contact::DisplayInfo& rDisplayInfo)
577 {
578 	SdrObject* pObject = rOriginal.GetViewContact().TryToGetSdrObject();
579 
580 	if (pObject==NULL || pObject->GetPage() == NULL)
581 	{
582 		// not a SdrObject visualisation (maybe e.g. page) or no page
583 		return sdr::contact::ViewObjectContactRedirector::createRedirectedPrimitive2DSequence(
584             rOriginal,
585             rDisplayInfo);
586     }
587 
588     const bool bDoCreateGeometry (pObject->GetPage()->checkVisibility( rOriginal, rDisplayInfo, true));
589 
590     if ( ! bDoCreateGeometry
591         && (pObject->GetObjInventor() != SdrInventor || pObject->GetObjIdentifier() != OBJ_PAGE))
592     {
593         return drawinglayer::primitive2d::Primitive2DSequence();
594     }
595 
596     if (pObject->IsEmptyPresObj())
597         return drawinglayer::primitive2d::Primitive2DSequence();
598 
599     return sdr::contact::ViewObjectContactRedirector::createRedirectedPrimitive2DSequence(
600         rOriginal,
601         rDisplayInfo);
602 }
603 
604 } // end of anonymous namespace
605 
606 
607 } // end of namespace ::sd
608