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