blob: 28a56ec5f28bb7a16ba0929afaa77e449883e461 [file] [log] [blame]
/**************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*************************************************************/
// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_sd.hxx"
#include "PreviewRenderer.hxx"
#include "DrawDocShell.hxx"
#include "drawdoc.hxx"
#include "drawview.hxx"
#include "sdpage.hxx"
#include "ViewShell.hxx"
#include <vcl/virdev.hxx>
#include <svx/svdpagv.hxx>
#include <svx/svdoutl.hxx>
#include <editeng/eeitem.hxx>
#include <editeng/editstat.hxx>
#include <tools/link.hxx>
#include <vcl/svapp.hxx>
#include <tools/diagnose_ex.h>
#include <svx/sdr/contact/viewobjectcontact.hxx>
#include <svx/sdr/contact/viewcontact.hxx>
using namespace ::com::sun::star;
using namespace ::com::sun::star::uno;
namespace sd {
const int PreviewRenderer::snSubstitutionTextSize = 11;
const int PreviewRenderer::snFrameWidth = 1;
namespace {
/** This incarnation of the ViewObjectContactRedirector filters away all
PageObj objects, unconditionally.
*/
class ViewRedirector : public ::sdr::contact::ViewObjectContactRedirector
{
public:
ViewRedirector (void);
virtual ~ViewRedirector (void);
virtual drawinglayer::primitive2d::Primitive2DSequence createRedirectedPrimitive2DSequence(
const sdr::contact::ViewObjectContact& rOriginal,
const sdr::contact::DisplayInfo& rDisplayInfo);
};
}
//===== PreviewRenderer =======================================================
PreviewRenderer::PreviewRenderer (
OutputDevice* pTemplate,
const bool bHasFrame)
: mpPreviewDevice (new VirtualDevice()),
mpView(NULL),
mpDocShellOfView(NULL),
mnWidthOfView(0),
maFrameColor (svtools::ColorConfig().GetColorValue(svtools::DOCBOUNDARIES).nColor),
mbHasFrame(bHasFrame)
{
if (pTemplate != NULL)
{
mpPreviewDevice->SetDigitLanguage (pTemplate->GetDigitLanguage());
mpPreviewDevice->SetBackground(pTemplate->GetBackground());
}
else
{
mpPreviewDevice->SetBackground(Wallpaper(
Application::GetSettings().GetStyleSettings().GetWindowColor()));
}
}
PreviewRenderer::~PreviewRenderer (void)
{
if (mpDocShellOfView != NULL)
EndListening (*mpDocShellOfView);
}
Image PreviewRenderer::RenderPage (
const SdPage* pPage,
const sal_Int32 nWidth,
const String& rSubstitutionText,
const bool bObeyHighContrastMode,
const bool bDisplayPresentationObjects)
{
if (pPage != NULL)
{
const Size aPageModelSize (pPage->GetSize());
const double nAspectRatio (
double(aPageModelSize.Width()) / double(aPageModelSize.Height()));
const sal_Int32 nFrameWidth (mbHasFrame ? snFrameWidth : 0);
const sal_Int32 nHeight (sal::static_int_cast<sal_Int32>(
(nWidth - 2*nFrameWidth) / nAspectRatio + 2*nFrameWidth + 0.5));
return RenderPage (
pPage,
Size(nWidth,nHeight),
rSubstitutionText,
bObeyHighContrastMode,
bDisplayPresentationObjects);
}
else
return Image();
}
Image PreviewRenderer::RenderPage (
const SdPage* pPage,
Size aPixelSize,
const String& rSubstitutionText,
const bool bObeyHighContrastMode,
const bool bDisplayPresentationObjects)
{
Image aPreview;
if (pPage != NULL)
{
try
{
if (Initialize(pPage, aPixelSize, bObeyHighContrastMode))
{
PaintPage(pPage, bDisplayPresentationObjects);
PaintSubstitutionText(rSubstitutionText);
PaintFrame();
Size aSize (mpPreviewDevice->GetOutputSizePixel());
aPreview = mpPreviewDevice->GetBitmap (
mpPreviewDevice->PixelToLogic(Point(0,0)),
mpPreviewDevice->PixelToLogic(aSize));
Cleanup();
}
}
catch (const com::sun::star::uno::Exception&)
{
DBG_UNHANDLED_EXCEPTION();
}
}
return aPreview;
}
Image PreviewRenderer::RenderSubstitution (
const Size& rPreviewPixelSize,
const String& rSubstitutionText)
{
Image aPreview;
try
{
// Set size.
mpPreviewDevice->SetOutputSizePixel(rPreviewPixelSize);
// Adjust contrast mode.
const bool bUseContrast (
Application::GetSettings().GetStyleSettings().GetHighContrastMode());
mpPreviewDevice->SetDrawMode (bUseContrast
? ViewShell::OUTPUT_DRAWMODE_CONTRAST
: ViewShell::OUTPUT_DRAWMODE_COLOR);
// Set a map mode that makes a typical substitution text completely
// visible.
MapMode aMapMode (mpPreviewDevice->GetMapMode());
aMapMode.SetMapUnit(MAP_100TH_MM);
const double nFinalScale (25.0 * rPreviewPixelSize.Width() / 28000.0);
aMapMode.SetScaleX(nFinalScale);
aMapMode.SetScaleY(nFinalScale);
const sal_Int32 nFrameWidth (mbHasFrame ? snFrameWidth : 0);
aMapMode.SetOrigin(mpPreviewDevice->PixelToLogic(
Point(nFrameWidth,nFrameWidth),aMapMode));
mpPreviewDevice->SetMapMode (aMapMode);
// Clear the background.
const Rectangle aPaintRectangle (
Point(0,0),
mpPreviewDevice->GetOutputSizePixel());
mpPreviewDevice->EnableMapMode(sal_False);
mpPreviewDevice->SetLineColor();
svtools::ColorConfig aColorConfig;
mpPreviewDevice->SetFillColor(aColorConfig.GetColorValue(svtools::DOCCOLOR).nColor);
mpPreviewDevice->DrawRect (aPaintRectangle);
mpPreviewDevice->EnableMapMode(sal_True);
// Paint substitution text and a frame around it.
PaintSubstitutionText (rSubstitutionText);
PaintFrame();
const Size aSize (mpPreviewDevice->GetOutputSizePixel());
aPreview = mpPreviewDevice->GetBitmap (
mpPreviewDevice->PixelToLogic(Point(0,0)),
mpPreviewDevice->PixelToLogic(aSize));
}
catch (const com::sun::star::uno::Exception&)
{
DBG_UNHANDLED_EXCEPTION();
}
return aPreview;
}
bool PreviewRenderer::Initialize (
const SdPage* pPage,
const Size& rPixelSize,
const bool bObeyHighContrastMode)
{
bool bSuccess = false;
do
{
if (pPage == NULL)
break;
SdrModel* pModel = pPage->GetModel();
if (pModel == NULL)
break;
SetupOutputSize(*pPage, rPixelSize);
SdDrawDocument* pDocument
= static_cast<SdDrawDocument*>(pPage->GetModel());
DrawDocShell* pDocShell = pDocument->GetDocSh();
// Create view
ProvideView (pDocShell);
if (mpView.get() == NULL)
break;
// Adjust contrast mode.
bool bUseContrast (bObeyHighContrastMode
&& Application::GetSettings().GetStyleSettings().GetHighContrastMode());
mpPreviewDevice->SetDrawMode (bUseContrast
? ViewShell::OUTPUT_DRAWMODE_CONTRAST
: ViewShell::OUTPUT_DRAWMODE_COLOR);
mpPreviewDevice->SetSettings(Application::GetSettings());
// Tell the view to show the given page.
SdPage* pNonConstPage = const_cast<SdPage*>(pPage);
if (pPage->IsMasterPage())
{
mpView->ShowSdrPage(mpView->GetModel()->GetMasterPage(pPage->GetPageNum()));
}
else
{
mpView->ShowSdrPage(pNonConstPage);
}
// Make sure that a page view exists.
SdrPageView* pPageView = mpView->GetSdrPageView();
if (pPageView == NULL)
break;
// #121224# No need to set SetApplicationBackgroundColor (which is the color
// of the area 'behind' the page (formally called 'Wiese') since the page previews
// produced exactly cover the page's area, so it would never be visible. What
// needs to be set is the ApplicationDocumentColor which is derived from
// svtools::DOCCOLOR normally
svtools::ColorConfig aColorConfig;
Color aApplicationDocumentColor;
if(!pPageView || pPageView->GetApplicationDocumentColor() == COL_AUTO)
{
svtools::ColorConfig aColorConfig;
aApplicationDocumentColor = aColorConfig.GetColorValue( svtools::DOCCOLOR ).nColor;
}
else
{
aApplicationDocumentColor = pPageView->GetApplicationDocumentColor();
}
pPageView->SetApplicationDocumentColor(aApplicationDocumentColor);
SdrOutliner& rOutliner(pDocument->GetDrawOutliner(NULL));
rOutliner.SetBackgroundColor(aApplicationDocumentColor);
rOutliner.SetDefaultLanguage(pDocument->GetLanguage(EE_CHAR_LANGUAGE));
mpPreviewDevice->SetBackground(Wallpaper(aApplicationDocumentColor));
mpPreviewDevice->Erase();
bSuccess = true;
}
while (false);
return bSuccess;
}
void PreviewRenderer::Cleanup (void)
{
mpView->HideSdrPage();
}
void PreviewRenderer::PaintPage (
const SdPage* pPage,
const bool bDisplayPresentationObjects)
{
// Paint the page.
Rectangle aPaintRectangle (Point(0,0), pPage->GetSize());
Region aRegion (aPaintRectangle);
// Turn off online spelling and redlining.
SdrOutliner* pOutliner = NULL;
sal_uLong nSavedControlWord (0);
if (mpDocShellOfView!=NULL && mpDocShellOfView->GetDoc()!=NULL)
{
pOutliner = &mpDocShellOfView->GetDoc()->GetDrawOutliner();
nSavedControlWord = pOutliner->GetControlWord();
pOutliner->SetControlWord((nSavedControlWord & ~EE_CNTRL_ONLINESPELLING));
}
// Use a special redirector to prevent PresObj shapes from being painted.
boost::scoped_ptr<ViewRedirector> pRedirector;
if ( ! bDisplayPresentationObjects)
pRedirector.reset(new ViewRedirector());
try
{
mpView->CompleteRedraw(mpPreviewDevice.get(), aRegion, pRedirector.get());
}
catch (const ::com::sun::star::uno::Exception&)
{
DBG_UNHANDLED_EXCEPTION();
}
// Restore the previous online spelling and redlining states.
if (pOutliner != NULL)
pOutliner->SetControlWord(nSavedControlWord);
}
void PreviewRenderer::PaintSubstitutionText (const String& rSubstitutionText)
{
if (rSubstitutionText.Len() > 0)
{
// Set the font size.
const Font& rOriginalFont (mpPreviewDevice->GetFont());
Font aFont (mpPreviewDevice->GetSettings().GetStyleSettings().GetAppFont());
sal_Int32 nHeight (mpPreviewDevice->PixelToLogic(Size(0,snSubstitutionTextSize)).Height());
aFont.SetHeight(nHeight);
mpPreviewDevice->SetFont (aFont);
// Paint the substitution text.
Rectangle aTextBox (
Point(0,0),
mpPreviewDevice->PixelToLogic(
mpPreviewDevice->GetOutputSizePixel()));
sal_uInt16 nTextStyle =
TEXT_DRAW_CENTER
| TEXT_DRAW_VCENTER
| TEXT_DRAW_MULTILINE
| TEXT_DRAW_WORDBREAK;
mpPreviewDevice->DrawText (aTextBox, rSubstitutionText, nTextStyle);
// Restore the font.
mpPreviewDevice->SetFont (rOriginalFont);
}
}
void PreviewRenderer::PaintFrame (void)
{
if (mbHasFrame)
{
// Paint a frame arround the preview.
Rectangle aPaintRectangle (
Point(0,0),
mpPreviewDevice->GetOutputSizePixel());
mpPreviewDevice->EnableMapMode(sal_False);
mpPreviewDevice->SetLineColor(maFrameColor);
mpPreviewDevice->SetFillColor();
mpPreviewDevice->DrawRect(aPaintRectangle);
mpPreviewDevice->EnableMapMode(sal_True);
}
}
void PreviewRenderer::SetupOutputSize (
const SdPage& rPage,
const Size& rFramePixelSize)
{
// First set the map mode to some arbitrary scale that is numerically
// stable.
MapMode aMapMode (mpPreviewDevice->GetMapMode());
aMapMode.SetMapUnit(MAP_PIXEL);
// Adapt it to the desired width.
const Size aPageModelSize (rPage.GetSize());
if (aPageModelSize.Width()>0 || aPageModelSize.Height()>0)
{
const sal_Int32 nFrameWidth (mbHasFrame ? snFrameWidth : 0);
aMapMode.SetScaleX(
Fraction(rFramePixelSize.Width()-2*nFrameWidth-1, aPageModelSize.Width()));
aMapMode.SetScaleY(
Fraction(rFramePixelSize.Height()-2*nFrameWidth-1, aPageModelSize.Height()));
aMapMode.SetOrigin(mpPreviewDevice->PixelToLogic(Point(nFrameWidth,nFrameWidth),aMapMode));
}
else
{
// We should never get here.
OSL_ASSERT(false);
aMapMode.SetScaleX(1.0);
aMapMode.SetScaleY(1.0);
}
mpPreviewDevice->SetMapMode (aMapMode);
mpPreviewDevice->SetOutputSizePixel(rFramePixelSize);
}
void PreviewRenderer::ProvideView (DrawDocShell* pDocShell)
{
if (pDocShell != mpDocShellOfView)
{
// Destroy the view that is connected to the current doc shell.
mpView.reset();
// Switch our attention, i.e. listening for DYING events, to
// the new doc shell.
if (mpDocShellOfView != NULL)
EndListening (*mpDocShellOfView);
mpDocShellOfView = pDocShell;
if (mpDocShellOfView != NULL)
StartListening (*mpDocShellOfView);
}
if (mpView.get() == NULL)
{
mpView.reset (new DrawView (pDocShell, mpPreviewDevice.get(), NULL));
}
mpView->SetPreviewRenderer(true);
#if 1
mpView->SetPageVisible(false);
mpView->SetPageBorderVisible(true);
mpView->SetBordVisible(false);
#else
// This works in the slide sorter but prevents the master page
// background being painted in the list of current master pages in the
// task manager.
mpView->SetPagePaintingAllowed(false);
#endif
}
Image PreviewRenderer::ScaleBitmap (
const BitmapEx& rBitmapEx,
int nWidth)
{
Image aPreview;
do
{
// Adjust contrast mode.
bool bUseContrast = Application::GetSettings().GetStyleSettings().
GetHighContrastMode();
mpPreviewDevice->SetDrawMode (bUseContrast
? ViewShell::OUTPUT_DRAWMODE_CONTRAST
: ViewShell::OUTPUT_DRAWMODE_COLOR);
// Set output size.
Size aSize (rBitmapEx.GetSizePixel());
if (aSize.Width() <= 0)
break;
Size aFrameSize (
nWidth,
(long)((nWidth*1.0 * aSize.Height()) / aSize.Width() + 0.5));
Size aPreviewSize (aFrameSize.Width()-2,aFrameSize.Height()-2);
MapMode aMapMode (mpPreviewDevice->GetMapMode());
aMapMode.SetMapUnit(MAP_PIXEL);
aMapMode.SetOrigin (Point());
aMapMode.SetScaleX (1.0);
aMapMode.SetScaleY (1.0);
mpPreviewDevice->SetMapMode (aMapMode);
mpPreviewDevice->SetOutputSize (aFrameSize);
// Paint a frame arround the preview.
mpPreviewDevice->SetLineColor (maFrameColor);
mpPreviewDevice->SetFillColor ();
mpPreviewDevice->DrawRect (Rectangle(Point(0,0), aFrameSize));
// Paint the bitmap scaled to the desired width.
BitmapEx aScaledBitmap (rBitmapEx.GetBitmap());
aScaledBitmap.Scale (aPreviewSize, BMP_SCALE_INTERPOLATE);
mpPreviewDevice->DrawBitmap (
Point(1,1),
aPreviewSize,
aScaledBitmap.GetBitmap());
// Get the resulting bitmap.
aPreview = mpPreviewDevice->GetBitmap (Point(0,0), aFrameSize);
}
while (false);
return aPreview;
}
void PreviewRenderer::Notify(SfxBroadcaster&, const SfxHint& rHint)
{
if (rHint.IsA(TYPE(SfxSimpleHint))
&& mpDocShellOfView != NULL)
{
const SfxSimpleHint* pSimpleHint = PTR_CAST(SfxSimpleHint, &rHint);
if (pSimpleHint != NULL
&& pSimpleHint->GetId() == SFX_HINT_DYING)
{
// The doc shell is dying. Our view uses its item pool and
// has to be destroyed as well. The next call to
// ProvideView will create a new one (for another
// doc shell, of course.)
mpView.reset();
mpDocShellOfView = NULL;
}
}
}
//===== ViewRedirector ========================================================
namespace {
ViewRedirector::ViewRedirector (void)
{
}
ViewRedirector::~ViewRedirector (void)
{
}
drawinglayer::primitive2d::Primitive2DSequence ViewRedirector::createRedirectedPrimitive2DSequence(
const sdr::contact::ViewObjectContact& rOriginal,
const sdr::contact::DisplayInfo& rDisplayInfo)
{
SdrObject* pObject = rOriginal.GetViewContact().TryToGetSdrObject();
if (pObject==NULL || pObject->GetPage() == NULL)
{
// not a SdrObject visualisation (maybe e.g. page) or no page
return sdr::contact::ViewObjectContactRedirector::createRedirectedPrimitive2DSequence(
rOriginal,
rDisplayInfo);
}
const bool bDoCreateGeometry (pObject->GetPage()->checkVisibility( rOriginal, rDisplayInfo, true));
if ( ! bDoCreateGeometry
&& (pObject->GetObjInventor() != SdrInventor || pObject->GetObjIdentifier() != OBJ_PAGE))
{
return drawinglayer::primitive2d::Primitive2DSequence();
}
if (pObject->IsEmptyPresObj())
return drawinglayer::primitive2d::Primitive2DSequence();
return sdr::contact::ViewObjectContactRedirector::createRedirectedPrimitive2DSequence(
rOriginal,
rDisplayInfo);
}
} // end of anonymous namespace
} // end of namespace ::sd