diff options
author | Caolán McNamara <caolanm@redhat.com> | 2015-03-19 14:43:08 +0000 |
---|---|---|
committer | Caolán McNamara <caolanm@redhat.com> | 2015-03-23 11:42:28 +0000 |
commit | e510a208b01c87a341b43d74d8d901f992379b84 (patch) | |
tree | 7f437b7d48e60ec14b0051993a9f2eb88f40bd53 /vcl/quartz | |
parent | 2b838285e206912374f464bd1ab8dc8a561f59f5 (diff) |
move cairo helpers to vcl and make per-plug
Change-Id: I4de4d5c3a191784598e93a8cf70e45a3f59ae857
Reviewed-on: https://gerrit.libreoffice.org/14907
Reviewed-by: Caolán McNamara <caolanm@redhat.com>
Tested-by: Caolán McNamara <caolanm@redhat.com>
Diffstat (limited to 'vcl/quartz')
-rw-r--r-- | vcl/quartz/cairo_quartz_cairo.cxx | 260 | ||||
-rw-r--r-- | vcl/quartz/cairo_quartz_cairo.hxx | 70 | ||||
-rw-r--r-- | vcl/quartz/salgdicommon.cxx | 113 |
3 files changed, 443 insertions, 0 deletions
diff --git a/vcl/quartz/cairo_quartz_cairo.cxx b/vcl/quartz/cairo_quartz_cairo.cxx new file mode 100644 index 000000000000..b3a05541c438 --- /dev/null +++ b/vcl/quartz/cairo_quartz_cairo.cxx @@ -0,0 +1,260 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +#include <config_cairo_canvas.h> + +#if ENABLE_CAIRO_CANVAS +/************************************************************************ + * Mac OS X/Quartz and iOS surface backend for LibreOffice Cairo Canvas * + ************************************************************************/ + +#include <osl/diagnose.h> +#include <vcl/sysdata.hxx> +#include <vcl/bitmap.hxx> +#include <vcl/virdev.hxx> + +#include "cairo_cairo.hxx" + +#include <config_cairo_canvas.h> + +#include "cairo_quartz_cairo.hxx" + +namespace cairo +{ + /** + * QuartzSurface::Surface: Create generic Canvas surface using given Cairo Surface + * + * @param pSurface Cairo Surface + * + * This constructor only stores data, it does no processing. + * It is used with e.g. cairo_image_surface_create_for_data() + * and QuartzSurface::getSimilar() + * + * Set the mpSurface to the new surface or NULL + **/ + QuartzSurface::QuartzSurface( const CairoSurfaceSharedPtr& pSurface ) : + mpView(NULL), + mpSurface( pSurface ) + { + // Necessary, context is lost otherwise + CGContextRetain( getCGContext() ); // == NULL for non-native surfaces + } + + /** + * QuartzSurface::Surface: Create Canvas surface from Window reference. + * @param NSView + * @param x horizontal location of the new surface + * @param y vertical location of the new surface + * @param width width of the new surface + * @param height height of the new surface + * + * pSysData contains the platform native Window reference. + * pSysData is used to create a surface on the Window + * + * Set the mpSurface to the new surface or NULL + **/ + QuartzSurface::QuartzSurface( NSView* pView, int x, int y, int width, int height ) : + mpView(pView), + mpSurface() + { + OSL_TRACE("Canvas::cairo::Surface(NSView*, x:%d, y:%d, w:%d, h:%d): New Surface for window", x, y, width, height); + + // on Mac OS X / Quartz we are not drawing directly to the screen, but via regular CGContextRef. + // The actual drawing to NSView (i.e. screen) is done in QuartzSurface::flush() + + // HACK: currently initial size for windowsurface is 0x0, which is not possible for us. + if (width == 0 || height == 0) { + width = [mpView bounds].size.width; + height = [mpView bounds].size.height; + OSL_TRACE("Canvas::cairo::Surface(): BUG!! size is ZERO! fixing to %d x %d...", width, height); + } + + // create a generic surface, NSView/Window is ARGB32. + mpSurface.reset( + cairo_quartz_surface_create(CAIRO_FORMAT_ARGB32, width, height), + &cairo_surface_destroy); + + cairo_surface_set_device_offset( mpSurface.get(), x, y ); + } + + /** + * QuartzSurface::Surface: Create Canvas surface from CGContextRef. + * @param CGContext Native graphics context + * @param x horizontal location of the new surface + * @param y vertical location of the new surface + * @param width width of the new surface + * @param height height of the new surface + * + * Set the mpSurface to the new surface or NULL + **/ + QuartzSurface::QuartzSurface( CGContextRef rContext, int x, int y, int width, int height ) : + mpView(NULL), + mpSurface() + { + OSL_TRACE("Canvas::cairo::Surface(CGContext:%p, x:%d, y:%d, w:%d, h:%d): New Surface.", rContext, x, y, width, height); + // create surface based on CGContext + + // ensure kCGBitmapByteOrder32Host flag, otherwise Cairo breaks (we are practically always using CGBitmapContext) + OSL_ASSERT ((CGBitmapContextGetBitsPerPixel(rContext) != 32) || + (CGBitmapContextGetBitmapInfo(rContext) & kCGBitmapByteOrderMask) == kCGBitmapByteOrder32Host); + + mpSurface.reset(cairo_quartz_surface_create_for_cg_context(rContext, width, height), + &cairo_surface_destroy); + + cairo_surface_set_device_offset( mpSurface.get(), x, y ); + + // Necessary, context is lost otherwise + CGContextRetain(rContext); + } + + + /** + * QuartzSurface::getCairo: Create Cairo (drawing object) for the Canvas surface + * + * @return new Cairo or NULL + **/ + CairoSharedPtr QuartzSurface::getCairo() const + { + if (mpSurface.get()) + { + return CairoSharedPtr( cairo_create(mpSurface.get()), + &cairo_destroy ); + } + else + { + return CairoSharedPtr(); + } + } + + /** + * QuartzSurface::getSimilar: Create new similar Canvas surface + * @param aContent format of the new surface (cairo_content_t from cairo/src/cairo.h) + * @param width width of the new surface + * @param height height of the new surface + * + * Creates a new Canvas surface. This normally creates platform native surface, even though + * generic function is used. + * + * Cairo surface from aContent (cairo_content_t) + * + * @return new surface or NULL + **/ + SurfaceSharedPtr QuartzSurface::getSimilar( Content aContent, int width, int height ) const + { + return SurfaceSharedPtr( + new QuartzSurface( + CairoSurfaceSharedPtr( + cairo_surface_create_similar( mpSurface.get(), aContent, width, height ), + &cairo_surface_destroy ))); + } + + /** + * QuartzSurface::flush: Draw the data to screen + **/ + void QuartzSurface::flush() const + { + // can only flush surfaces with NSView + if( !mpView ) + return; + + OSL_TRACE("Canvas::cairo::QuartzSurface::flush(): flush to NSView"); + + CGContextRef mrContext = getCGContext(); + + if (!mrContext) + return; +#ifndef IOS + [mpView lockFocus]; +#endif + +#ifndef IOS + /** + * This code is using same screen update code as in VCL (esp. AquaSalGraphics::UpdateWindow() ) + */ + CGContextRef rViewContext = reinterpret_cast<CGContextRef>([[NSGraphicsContext currentContext] graphicsPort]); +#else + // Just guessing for now... + CGContextRef rViewContext = UIGraphicsGetCurrentContext(); +#endif + CGImageRef xImage = CGBitmapContextCreateImage(mrContext); + CGContextDrawImage(rViewContext, + CGRectMake( 0, 0, + CGImageGetWidth(xImage), + CGImageGetHeight(xImage)), + xImage); + CGImageRelease( xImage ); + CGContextFlush( rViewContext ); +#ifndef IOS + [mpView unlockFocus]; +#endif + } + + /** + * QuartzSurface::getDepth: Get the color depth of the Canvas surface. + * + * @return color depth + **/ + int QuartzSurface::getDepth() const + { + if (mpSurface.get()) + { + switch (cairo_surface_get_content (mpSurface.get())) + { + case CAIRO_CONTENT_ALPHA: return 8; break; + case CAIRO_CONTENT_COLOR: return 24; break; + case CAIRO_CONTENT_COLOR_ALPHA: return 32; break; + } + } + OSL_TRACE("Canvas::cairo::QuartzSurface::getDepth(): ERROR - depth unspecified!"); + + return -1; + } + + /** + * QuartzSurface::getCGContext: Get the native CGContextRef of the Canvas's cairo surface + * + * @return graphics context + **/ + CGContextRef QuartzSurface::getCGContext() const + { + if (mpSurface.get()) + return cairo_quartz_surface_get_cg_context(mpSurface.get()); + else + return NULL; + } + + /** + * cairo::createVirtualDevice: Create a VCL virtual device for the CGContext in the cairo Surface + * + * @return The new virtual device + **/ + boost::shared_ptr<VirtualDevice> QuartzSurface::createVirtualDevice() const + { + SystemGraphicsData aSystemGraphicsData; + aSystemGraphicsData.nSize = sizeof(SystemGraphicsData); + aSystemGraphicsData.rCGContext = getCGContext(); + return boost::shared_ptr<VirtualDevice>( + new VirtualDevice( &aSystemGraphicsData, Size(1, 1), getDepth() )); + } + +} // namespace cairo + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/quartz/cairo_quartz_cairo.hxx b/vcl/quartz/cairo_quartz_cairo.hxx new file mode 100644 index 000000000000..a3f94d20abf3 --- /dev/null +++ b/vcl/quartz/cairo_quartz_cairo.hxx @@ -0,0 +1,70 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +#ifndef INCLUDED_CANVAS_SOURCE_CAIRO_CAIRO_QUARTZ_CAIRO_HXX +#define INCLUDED_CANVAS_SOURCE_CAIRO_CAIRO_QUARTZ_CAIRO_HXX + +#include "cairo_cairo.hxx" + +#include "premac.h" +#include <TargetConditionals.h> +#if !defined(TARGET_OS_IPHONE) || !TARGET_OS_IPHONE +# include <Cocoa/Cocoa.h> +#else +# include <UIKit/UIKit.h> +# define NSView UIView +#endif +#include <cairo-quartz.h> +#include "postmac.h" + +namespace cairo { + + class QuartzSurface : public Surface + { + NSView* mpView; // if NULL - bg surface + CairoSurfaceSharedPtr mpSurface; + + public: + /// takes over ownership of passed cairo_surface + explicit QuartzSurface( const CairoSurfaceSharedPtr& pSurface ); + + /// create surface on subarea of given CGContext + explicit QuartzSurface( CGContextRef rContext, int x, int y, int width, int height ); + + /// create a offscreen surface for given NSView + QuartzSurface( NSView* pView, int x, int y, int width, int height ); + + // Surface interface + virtual CairoSharedPtr getCairo() const; + virtual CairoSurfaceSharedPtr getCairoSurface() const { return mpSurface; } + virtual SurfaceSharedPtr getSimilar( Content aContent, int width, int height ) const; + + virtual boost::shared_ptr<VirtualDevice> createVirtualDevice() const; + + virtual void flush() const; + + int getDepth() const; + + CGContextRef getCGContext() const; + }; +} + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/quartz/salgdicommon.cxx b/vcl/quartz/salgdicommon.cxx index b982dd4ff7bb..febf2fdc569a 100644 --- a/vcl/quartz/salgdicommon.cxx +++ b/vcl/quartz/salgdicommon.cxx @@ -39,6 +39,11 @@ #include <vcl/sysdata.hxx> #endif +#include <config_cairo_canvas.h> +#if ENABLE_CAIRO_CANVAS +#include "cairo_quartz_cairo.hxx" +#endif + #if defined(IOS) && defined(DBG_UTIL) // Variables in TiledView.m @@ -1447,7 +1452,115 @@ SystemGraphicsData AquaSalGraphics::GetGraphicsData() const bool AquaSalGraphics::SupportsCairo() const { +#if ENABLE_CAIRO_CANVAS return true; +#else + return false; +#endif +} + +/** + * cairo::createSurface: Create generic Canvas surface using given Cairo Surface + * + * @param rSurface Cairo Surface + * + * @return new Surface + */ +cairo::SurfaceSharedPtr AquaSalGraphics::CreateSurface(const cairo::CairoSurfaceSharedPtr& rSurface) const +{ +#if ENABLE_CAIRO_CANVAS + return cairo::SurfaceSharedPtr(new cairo::QuartzSurface(rSurface)); +#else + (void)rSurface; + return cairo::SurfaceSharedPtr(); +#endif +} + +/** + * cairo::createSurface: Create Canvas surface using given VCL Window or Virtualdevice + * + * @param rSurface Cairo Surface + * + * For VCL Window, use platform native system environment data (struct SystemEnvData in vcl/inc/sysdata.hxx) + * For VCL Virtualdevice, use platform native system graphics data (struct SystemGraphicsData in vcl/inc/sysdata.hxx) + * + * @return new Surface + */ +cairo::SurfaceSharedPtr AquaSalGraphics::CreateSurface( const OutputDevice& rRefDevice, + int x, int y, int width, int height ) const +{ + cairo::SurfaceSharedPtr surf; +#if ENABLE_CAIRO_CANVAS + if( rRefDevice.GetOutDevType() == OUTDEV_WINDOW ) + { + const vcl::Window &rWindow = (const vcl::Window &) rRefDevice; + const SystemEnvData* pSysData = GetSysData(&rWindow); + if (pSysData) + surf = cairo::SurfaceSharedPtr(new cairo::QuartzSurface(pSysData->pView, x, y, width, height)); + } + else if( rRefDevice.GetOutDevType() == OUTDEV_VIRDEV ) + { + SystemGraphicsData aSysData = ((const VirtualDevice&) rRefDevice).GetSystemGfxData(); + + if (aSysData.rCGContext) + surf = cairo::SurfaceSharedPtr(new cairo::QuartzSurface(aSysData.rCGContext, x, y, width, height)); + } +#else + (void)rRefDevice; + (void)x; + (void)y; + (void)width; + (void)height; +#endif + return surf; +} + +/** + * cairo::createBitmapSurface: Create platform native Canvas surface from BitmapSystemData + * @param OutputDevice (not used) + * @param rData Platform native image data (struct BitmapSystemData in vcl/inc/bitmap.hxx) + * @param rSize width and height of the new surface + * + * Create a surface based on image data on rData + * + * @return new surface or empty surface + **/ +cairo::SurfaceSharedPtr AquaSalGraphics::CreateBitmapSurface( const OutputDevice& /* rRefDevice */, + const BitmapSystemData& rData, + const Size& rSize ) const +{ +#if ENABLE_CAIRO_CANVAS + OSL_TRACE( "requested size: %d x %d available size: %d x %d", + rSize.Width(), rSize.Height(), rData.mnWidth, rData.mnHeight ); + + if ( rData.mnWidth == rSize.Width() && rData.mnHeight == rSize.Height() ) + { + CGContextRef rContext = (CGContextRef)rData.rImageContext; + OSL_TRACE("Canvas::cairo::createBitmapSurface(): New native image surface, context = %p.", rData.rImageContext); + + return cairo::SurfaceSharedPtr(new cairo::QuartzSurface(rContext, 0, 0, rData.mnWidth, rData.mnHeight)); + } +#else + (void)rData; + (void)rSize; +#endif + return cairo::SurfaceSharedPtr(); +} + +css::uno::Any AquaSalGraphics::GetNativeSurfaceHandle(cairo::SurfaceSharedPtr& rSurface, const ::basegfx::B2ISize& /*rSize*/) const +{ + sal_IntPtr handle; +#if ENABLE_CAIRO_CANVAS + cairo::QuartzSurface* pQuartzSurface = dynamic_cast<cairo::QuartzSurface*>(rSurface.get()); + OSL_ASSERT(pQuartzSurface); + handle = sal_IntPtr (pQuartzSurface->getCGContext()); +#else + handle = 0; + (void)rSurface; +#endif + css::uno::Sequence< css::uno::Any > args( 1 ); + args[0] = css::uno::Any( handle ); + return css::uno::Any( args ); } long AquaSalGraphics::GetGraphicsWidth() const |