diff options
author | Tor Lillqvist <tml@iki.fi> | 2012-04-14 22:15:30 +0200 |
---|---|---|
committer | Tor Lillqvist <tml@iki.fi> | 2012-04-15 11:56:47 +0200 |
commit | 83ba7b4e8f67cc3a21fbaf476621af509032ae47 (patch) | |
tree | aaec12fd4e53165fd5309bf2f2c6b6a96f754c57 | |
parent | 640b8ebb668d466f348329915deba874e15e4b8f (diff) |
Copy and adapt current state of Norbert's CoreText work for iOS
Compiles, but I obviously have no idea how it works yet.
Yes, eventually we should factor out common parts from the iOS and
MacOSX code.
-rw-r--r-- | canvas/source/cairo/cairo_textlayout.cxx | 6 | ||||
-rw-r--r-- | vcl/Library_vcl.mk | 2 | ||||
-rw-r--r-- | vcl/inc/ios/common.h | 34 | ||||
-rw-r--r-- | vcl/inc/ios/salcoretextfontutils.hxx | 53 | ||||
-rw-r--r-- | vcl/inc/ios/salcoretextlayout.hxx | 90 | ||||
-rw-r--r-- | vcl/inc/ios/salcoretextstyle.hxx | 42 | ||||
-rw-r--r-- | vcl/inc/ios/salgdi.h | 392 | ||||
-rw-r--r-- | vcl/inc/ios/salgdicommon.hxx | 84 | ||||
-rw-r--r-- | vcl/inc/vcl/sysdata.hxx | 2 | ||||
-rw-r--r-- | vcl/ios/source/gdi/salcoretextfontutils.cxx | 609 | ||||
-rw-r--r-- | vcl/ios/source/gdi/salcoretextlayout.cxx | 632 | ||||
-rw-r--r-- | vcl/ios/source/gdi/salcoretextstyle.cxx | 96 | ||||
-rw-r--r-- | vcl/ios/source/gdi/salgdi.cxx | 2412 | ||||
-rw-r--r-- | vcl/ios/source/gdi/salgdicommon.cxx | 1581 | ||||
-rw-r--r-- | vcl/ios/source/gdi/salgdiutils.cxx | 8 |
15 files changed, 3216 insertions, 2827 deletions
diff --git a/canvas/source/cairo/cairo_textlayout.cxx b/canvas/source/cairo/cairo_textlayout.cxx index 063dc0d5cfb9..30493f9e2e63 100644 --- a/canvas/source/cairo/cairo_textlayout.cxx +++ b/canvas/source/cairo/cairo_textlayout.cxx @@ -65,6 +65,10 @@ # error Native API needed. #endif +#ifdef IOS +#include <CoreText/CoreText.h> +#endif + using namespace ::cairo; using namespace ::com::sun::star; @@ -507,7 +511,7 @@ namespace cairocanvas // when CGFont (Mac OS X 10.5 API) is provided by the AQUA VCL backend. font_face = cairo_quartz_font_face_create_for_atsu_font_id((ATSUFontID) rSysFontData.aATSUFontID); # else // iOS - font_face = cairo_quartz_font_face_create_for_cgfont( rSysFontData.rFont); + font_face = cairo_quartz_font_face_create_for_cgfont( CTFontCopyGraphicsFont( (CTFontRef) rSysFontData.rCTFont, NULL ) ); # endif #elif defined CAIRO_HAS_WIN32_SURFACE diff --git a/vcl/Library_vcl.mk b/vcl/Library_vcl.mk index 71944202e634..d85bd9920de4 100644 --- a/vcl/Library_vcl.mk +++ b/vcl/Library_vcl.mk @@ -523,8 +523,10 @@ $(eval $(call gb_Library_add_exception_objects,vcl,\ vcl/ios/source/dtrans/service_entry \ vcl/ios/source/gdi/salcoretextfontutils \ vcl/ios/source/gdi/salcoretextlayout \ + vcl/ios/source/gdi/salcoretextstyle \ vcl/ios/source/gdi/salbmp \ vcl/ios/source/gdi/salgdi \ + vcl/ios/source/gdi/salgdicommon \ vcl/ios/source/gdi/salnativewidgets \ vcl/ios/source/gdi/salgdiutils \ vcl/ios/source/gdi/salvd \ diff --git a/vcl/inc/ios/common.h b/vcl/inc/ios/common.h new file mode 100644 index 000000000000..8323df22bb70 --- /dev/null +++ b/vcl/inc/ios/common.h @@ -0,0 +1,34 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + +#ifndef _VCL_IOS_COMMON_H +#define _VCL_IOS_COMMON_H + +#include <sal/types.h> +#include <premac.h> +#include <CoreGraphics/CoreGraphics.h> +#include <CoreText/CoreText.h> +#include <UIKit/UIKit.h> +#include <postmac.h> +#include <tools/debug.hxx> + +// CoreFoundation designers, in their wisdom, decided that CFRelease of NULL +// cause a Crash, yet few API can return NULL when asking for the creation +// of an object, which force us to peper the code with egly if construct everywhere +// and open the door to very nasty crash on rare occasion +// this macro hide the mess +#define SafeCFRelease(a) do { if(a) { CFRelease(a); (a)=NULL; } } while(false) + + +#define round_to_long(a) ((a) >= 0 ? ((long)((a) + 0.5)) : ((long)((a) - 0.5))) + +#include "vcl/salgtype.hxx" + +#endif/* _VCL_IOS_COMMON_H */ + +//#define msgs_debug(c,f,...) +// fprintf(stderr, "%s::%s(%p:%04.4x)\n", this, #c, __func__, 0, __VA_ARGS__ ) + +#define msgs_debug(c,f,...) \ + fprintf(stderr, "%s::%s(%p:%4.4u)" f "\n", #c, __func__, this, ((unsigned int)pthread_self() & 8191), ##__VA_ARGS__ ); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/ios/salcoretextfontutils.hxx b/vcl/inc/ios/salcoretextfontutils.hxx index ed94b91ecfe5..bcc399c5c1f6 100644 --- a/vcl/inc/ios/salcoretextfontutils.hxx +++ b/vcl/inc/ios/salcoretextfontutils.hxx @@ -26,17 +26,48 @@ * ************************************************************************/ -#ifndef _SV_SALCORETEXTFONTUTILS_HXX -#define _SV_SALCORETEXTFONTUTILS_HXX +#ifndef _VCL_IOS_CORETEXT_SALCORETEXTFONTUTILS_HXX +#define _VCL_IOS_CORETEXT_SALCORETEXTFONTUTILS_HXX -class ImplIosFontData; +class ImplCoreTextFontData; class ImplDevFontList; -#include <premac.h> -#include <CoreText/CoreText.h> -#include <postmac.h> +#include <boost/unordered_map.hpp> -#include <map> +#include <vcl/fontcapabilities.hxx> + +#include "outfont.hxx" +#include "impfont.hxx" + +class ImplCoreTextFontData : public ImplFontData +{ +public: + ImplCoreTextFontData(const ImplDevFontAttributes&, CTFontRef font); + virtual ~ImplCoreTextFontData(); + virtual ImplFontData* Clone() const; + virtual ImplFontEntry* CreateFontInstance( FontSelectPattern& ) const; + virtual sal_IntPtr GetFontId() const { return (sal_IntPtr)m_CTFontRef;}; + CTFontRef GetCTFont() const { return m_CTFontRef; }; + const ImplFontCharMap* GetImplFontCharMap(); + bool GetImplFontCapabilities(vcl::FontCapabilities &rFontCapabilities); + bool HasChar( sal_uInt32 cChar ) const; + void ReadOs2Table(); + void ReadIosCmapEncoding(); + bool HasCJKSupport(); + bool GetRawFontData( std::vector<unsigned char>& rBuffer, bool* pJustCFF ) const; + +private: + void DetermineCJKSupport_OS2(CFDataRef rOS2Table); + void DetermineCJKSupport_cmap(CFDataRef rCmapTable); + CTFontRef m_CTFontRef; + mutable const ImplFontCharMap* m_pCharMap; + mutable vcl::FontCapabilities m_aFontCapabilities; + mutable bool m_bHasOs2Table; + mutable bool m_bOs2TableRead; + mutable bool m_bCmapTableRead; // true if cmap encoding of Mac font is read + mutable bool m_bHasCJKSupport; // #i78970# CJK fonts need extra leading + mutable bool m_bFontCapabilitiesRead; +}; /* This class has the responsibility of assembling a list of CoreText fonts available on the system and enabling access to that list. @@ -48,15 +79,15 @@ public: ~SystemFontList(); void AnnounceFonts( ImplDevFontList& ) const; - ImplIosFontData* GetFontDataFromRef( CTFontRef ) const; + ImplCoreTextFontData* GetFontDataFromRef( CTFontRef ) const; private: - typedef boost::unordered_map<CTFontRef,ImplIosFontData*> IosFontContainer; - IosFontContainer maFontContainer; + typedef boost::unordered_map<CTFontRef,ImplCoreTextFontData*> CoreTextFontContainer; + CoreTextFontContainer m_aFontContainer; void InitGlyphFallbacks(); }; -#endif // _SV_SALCORETEXTFONTUTILS_HXX +#endif // _VCL_IOS_CORETEXT_SALCORETEXTFONTUTILS_HXX /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/ios/salcoretextlayout.hxx b/vcl/inc/ios/salcoretextlayout.hxx new file mode 100644 index 000000000000..523d826d7047 --- /dev/null +++ b/vcl/inc/ios/salcoretextlayout.hxx @@ -0,0 +1,90 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _VCL_IOS_CORETEXT_SALCORETEXTLAYOUT_HXX +#define _VCL_IOS_CORETEXT_SALCORETEXTLAYOUT_HXX + +#include <tools/poly.hxx> + +#include "sallayout.hxx" + +class IosSalGraphics; +class CoreTextStyleInfo; + +class CoreTextLayout : public SalLayout +{ +public: + CoreTextLayout( IosSalGraphics* graphics, CoreTextStyleInfo* style); + virtual ~CoreTextLayout(); + + virtual void AdjustLayout( ImplLayoutArgs& ); + virtual void DrawText( SalGraphics& ) const; + virtual void DropGlyph( int nStart ); + virtual long FillDXArray( long* pDXArray ) const; + virtual bool GetBoundRect( SalGraphics&, Rectangle& ) const; + virtual void GetCaretPositions( int nArraySize, long* pCaretXArray ) const; + virtual bool GetGlyphOutlines( SalGraphics&, PolyPolyVector& ) const; + virtual int GetNextGlyphs( int nLen, sal_GlyphId* pGlyphs, Point& rPos, int&, + sal_Int32* pGlyphAdvances, int* pCharIndexes ) const; + virtual int GetTextBreak( long nMaxWidth, long nCharExtra, int nFactor ) const; + virtual long GetTextWidth() const; + virtual void InitFont() const; + virtual bool LayoutText( ImplLayoutArgs& ); + virtual void MoveGlyph( int nStart, long nNewXPos ); + virtual void Simplify( bool bIsBase ); + +private: + void Clean(); + bool InitGIA() const; + + IosSalGraphics* m_graphics; + CoreTextStyleInfo* m_style; + mutable int m_glyphs_count; + mutable int m_chars_count; + mutable int* m_chars2glyphs; + mutable int* m_glyphs2chars; + mutable CGGlyph* m_glyphs; + mutable int* m_char_widths; + mutable int* m_glyph_advances; + mutable CGPoint* m_glyph_positions; + CTTypesetterRef m_typesetter; + CTLineRef m_line; + mutable bool m_has_bound_rec; + mutable Rectangle m_bound_rect; + CGFloat m_base_advance; + mutable CGFloat m_cached_width; + mutable CFIndex m_current_run_index; + mutable CFIndex m_current_glyph_index; + mutable CFIndex m_current_glyphrun_index; + mutable CFArrayRef m_runs; + +}; + +#endif // _VCL_IOS_CORETEXT_SALCORETEXTLAYOUT_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/ios/salcoretextstyle.hxx b/vcl/inc/ios/salcoretextstyle.hxx new file mode 100644 index 000000000000..3cdade121582 --- /dev/null +++ b/vcl/inc/ios/salcoretextstyle.hxx @@ -0,0 +1,42 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + +#ifndef _VCL_AQUA_CORETEXT_SALCORETEXTSTYLE_HXX +#define _VCL_AQUA_CORETEXT_SALCORETEXTSTYLE_HXX + +#include "ios/salgdicommon.hxx" + +class FontSelectPattern; +class ImplCoreTextFontData; + +class CoreTextStyleInfo +{ +public: + CoreTextStyleInfo(); + ~CoreTextStyleInfo(); + CTFontRef GetFont() const { return m_CTFont; }; + long GetFontStretchedSize() const; + float GetFontStretchFactor() const { return m_stretch_factor; }; + CTParagraphStyleRef GetParagraphStyle() const { return m_CTParagraphStyle; } ; + CGSize GetSize() const; + CGColorRef GetColor() const { return m_color; } ; + void SetColor(SalColor color); + void SetColor(void); + void SetFont(FontSelectPattern* requested_font); + +private: + bool m_fake_bold; + bool m_fake_italic; + CGAffineTransform m_matrix; + float m_stretch_factor; + float m_font_scale; + float m_fake_dpi_scale; + CTParagraphStyleRef m_CTParagraphStyle; + CTFontRef m_CTFont; + CGColorRef m_color; + const ImplCoreTextFontData* m_font_data; + +}; + +#endif // _VCL_AQUA_CORETEXT_SALCORETEXTSTYLE_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/ios/salgdi.h b/vcl/inc/ios/salgdi.h index 576a8df883b9..2828b4e0f1b5 100644 --- a/vcl/inc/ios/salgdi.h +++ b/vcl/inc/ios/salgdi.h @@ -26,262 +26,206 @@ * ************************************************************************/ -#ifndef _SV_SALGDI_H -#define _SV_SALGDI_H +#ifndef _VCL_IOS_SALGDI_H +#define _VCL_IOS_SALGDI_H #include "basegfx/polygon/b2dpolypolygon.hxx" #include "ios/iosvcltypes.h" -#include <vcl/fontcapabilities.hxx> - -#include "outfont.hxx" +#include "ios/salcoretextfontutils.hxx" +#include "ios/salframe.h" #include "salgdi.hxx" -#include <vector> - -class IosSalFrame; -class IosSalBitmap; -class ImplDevFontAttributes; - -struct CGRect; - -// mac specific physically available font face -class ImplIosFontData : public ImplFontData -{ -public: - ImplIosFontData( const ImplDevFontAttributes&, CTFontRef ); - - virtual ~ImplIosFontData(); - - virtual ImplFontData* Clone() const; - virtual ImplFontEntry* CreateFontInstance( FontSelectPattern& ) const; - virtual sal_IntPtr GetFontId() const; - - const ImplFontCharMap* GetImplFontCharMap() const; - bool GetImplFontCapabilities(vcl::FontCapabilities &rFontCapabilities) const; - bool HasChar( sal_uInt32 cChar ) const; +#include "ios/salgdicommon.hxx" - void ReadOs2Table() const; - void ReadIosCmapEncoding() const; - bool HasCJKSupport() const; - -protected: - friend class IosSalGraphics; - const CTFontRef mpFontRef; - -private: - mutable const ImplFontCharMap* mpCharMap; - mutable vcl::FontCapabilities maFontCapabilities; - mutable bool mbOs2Read; // true if OS2-table related info is valid - mutable bool mbHasOs2Table; - mutable bool mbCmapEncodingRead; // true if cmap encoding of Ios font is read - mutable bool mbHasCJKSupport; // #i78970# CJK fonts need extra leading - mutable bool mbFontCapabilitiesRead; -}; - -// abstracting quartz color instead of having to use an CGFloat[] array -class RGBAColor -{ -public: - RGBAColor( SalColor ); - RGBAColor( float fRed, float fGreen, float fBlue, float fAlpha ); //NOTUSEDYET - const float* AsArray() const { return &mfRed; } - bool IsVisible() const { return (mfAlpha > 0); } - void SetAlpha( float fAlpha ) { mfAlpha = fAlpha; } -private: - float mfRed, mfGreen, mfBlue, mfAlpha; -}; +class CoreTextStyleInfo; // ------------------- // - IosSalGraphics - // ------------------- class IosSalGraphics : public SalGraphics { + friend class CoreTextLayout; protected: - IosSalFrame* mpFrame; - CGLayerRef mxLayer; // Quartz graphics layer - CGContextRef mrContext; // Quartz drawing context - class XorEmulation* mpXorEmulation; - int mnXorMode; // 0: off 1: on 2: invert only - int mnWidth; - int mnHeight; - int mnBitmapDepth; // zero unless bitmap - /// device resolution of this graphics - long mnRealDPIX; - long mnRealDPIY; + IosSalFrame* mpFrame; + CGLayerRef mxLayer; //< Quartz graphics layer + CGContextRef mrContext; //< Quartz drawing context + class XorEmulation* mpXorEmulation; + int mnXorMode; //< 0: off 1: on 2: invert only + int mnWidth; + int mnHeight; + int mnBitmapDepth; //< zero unless bitmap + long mnRealDPIX; //< device X-resolution of this graphics + long mnRealDPIY; //< device Y-resolution of this graphics + /// some graphics implementations (e.g. IosSalInfoPrinter) scale /// everything down by a factor (see SetupPrinterGraphics for details) /// so we have to compensate for it with the inverse factor - double mfFakeDPIScale; + double mfFakeDPIScale; + double mfFontScale; + - /// path representing current clip region - CGMutablePathRef mxClipPath; + CGMutablePathRef mxClipPath; //< path representing current clip region /// Drawing colors - /// pen color RGBA - RGBAColor maLineColor; - /// brush color RGBA - RGBAColor maFillColor; - - // Device Font settings - const ImplIosFontData* mpIosFontData; - /// Font attributes ??? - NSMutableDictionary* mpAttributes; - // text color - SalColor mnColor; - /// text rotation ??? - Fixed mnRotation; - /// <1.0: font is squeezed, >1.0 font is stretched, else 1.0 - float mfFontStretch; - /// allows text to be rendered without antialiasing - bool mbNonAntialiasedText; + RGBAColor maLineColor; //< pen color RGBA + RGBAColor maFillColor; //< brush color RGBA + + ImplCoreTextFontData* m_pCoreTextFontData; //< Device Font settings + + bool mbNonAntialiasedText; //< allows text to be rendered without antialiasing // Graphics types - /// is this a printer graphics - bool mbPrinter; - /// is this a virtual device graphics - bool mbVirDev; - /// is this a window graphics - bool mbWindow; + bool mbPrinter; //< is this a printer graphics + bool mbVirDev; //< is this a virtual device graphics + bool mbWindow; //< is this a window graphics + + CoreTextStyleInfo* m_style; public: IosSalGraphics(); virtual ~IosSalGraphics(); - bool IsPenVisible() const { return maLineColor.IsVisible(); } - bool IsBrushVisible() const { return maFillColor.IsVisible(); } + bool IsPenVisible() const { return maLineColor.IsVisible(); } + bool IsBrushVisible() const { return maFillColor.IsVisible(); } - void SetWindowGraphics( IosSalFrame* pFrame ); - void SetPrinterGraphics( CGContextRef, long nRealDPIX, long nRealDPIY, double fFakeScale ); - void SetVirDevGraphics( CGLayerRef, CGContextRef, int nBitDepth = 0 ); + void SetWindowGraphics( IosSalFrame* pFrame ); + void SetPrinterGraphics( CGContextRef, long nRealDPIX, long nRealDPIY, double fFakeScale ); + void SetVirDevGraphics( CGLayerRef, CGContextRef, int nBitDepth = 0 ); - void initResolution( UIWindow* ); - void copyResolution( IosSalGraphics& ); - void updateResolution(); + void initResolution( UIWindow* ); + void copyResolution( IosSalGraphics& ); + void updateResolution(); - bool IsWindowGraphics() const { return mbWindow; } - bool IsPrinterGraphics() const { return mbPrinter; } - bool IsVirDevGraphics() const { return mbVirDev; } - IosSalFrame* getGraphicsFrame() const { return mpFrame; } - void setGraphicsFrame( IosSalFrame* pFrame ) { mpFrame = pFrame; } + bool IsWindowGraphics() const { return mbWindow; } + bool IsPrinterGraphics() const { return mbPrinter; } + bool IsVirDevGraphics() const { return mbVirDev; } + IosSalFrame* getGraphicsFrame() const { return mpFrame; } + void setGraphicsFrame( IosSalFrame* pFrame ) { mpFrame = pFrame; } - void ImplDrawPixel( long nX, long nY, const RGBAColor& ); // helper to draw single pixels + void ImplDrawPixel( long nX, long nY, const RGBAColor& ); // helper to draw single pixels - bool CheckContext(); - void UpdateWindow( CGRect& ); // delivered in NSView coordinates - void RefreshRect( const CGRect& ); - void RefreshRect(float lX, float lY, float lWidth, float lHeight); + bool CheckContext(); + CGContextRef GetContext(); + void UpdateWindow( CGRect& ); // delivered in UIView coordinates + void RefreshRect( const CGRect& ); + void RefreshRect(float lX, float lY, float lWidth, float lHeight); - void SetState(); - void UnsetState(); + void SetState(); + void UnsetState(); // InvalidateContext does an UnsetState and sets mrContext to 0 - void InvalidateContext(); + void InvalidateContext(); - virtual bool setClipRegion( const Region& ); + virtual bool setClipRegion( const Region& ); // draw --> LineColor and FillColor and RasterOp and ClipRegion - virtual void drawPixel( long nX, long nY ); - virtual void drawPixel( long nX, long nY, SalColor nSalColor ); - virtual void drawLine( long nX1, long nY1, long nX2, long nY2 ); - virtual void drawRect( long nX, long nY, long nWidth, long nHeight ); - virtual void drawPolyLine( sal_uLong nPoints, const SalPoint* pPtAry ); - virtual void drawPolygon( sal_uLong nPoints, const SalPoint* pPtAry ); - virtual void drawPolyPolygon( sal_uLong nPoly, const sal_uLong* pPoints, PCONSTSALPOINT* pPtAry ); - virtual bool drawPolyPolygon( const ::basegfx::B2DPolyPolygon&, double fTransparency ); - virtual sal_Bool drawPolyLineBezier( sal_uLong nPoints, const SalPoint* pPtAry, const sal_uInt8* pFlgAry ); - virtual sal_Bool drawPolygonBezier( sal_uLong nPoints, const SalPoint* pPtAry, const sal_uInt8* pFlgAry ); - virtual sal_Bool drawPolyPolygonBezier( sal_uLong nPoly, const sal_uLong* pPoints, const SalPoint* const* pPtAry, const sal_uInt8* const* pFlgAry ); - virtual bool drawPolyLine( const ::basegfx::B2DPolygon&, double fTransparency, const ::basegfx::B2DVector& rLineWidths, basegfx::B2DLineJoin ); + virtual void drawPixel( long nX, long nY ); + virtual void drawPixel( long nX, long nY, SalColor nSalColor ); + virtual void drawLine( long nX1, long nY1, long nX2, long nY2 ); + virtual void drawRect( long nX, long nY, long nWidth, long nHeight ); + virtual void drawPolyLine( sal_uLong nPoints, const SalPoint* pPtAry ); + virtual void drawPolygon( sal_uLong nPoints, const SalPoint* pPtAry ); + virtual void drawPolyPolygon( sal_uLong nPoly, const sal_uLong* pPoints, PCONSTSALPOINT* pPtAry ); + virtual bool drawPolyPolygon( const ::basegfx::B2DPolyPolygon&, double fTransparency ); + virtual sal_Bool drawPolyLineBezier( sal_uLong nPoints, const SalPoint* pPtAry, const sal_uInt8* pFlgAry ); + virtual sal_Bool drawPolygonBezier( sal_uLong nPoints, const SalPoint* pPtAry, const sal_uInt8* pFlgAry ); + virtual sal_Bool drawPolyPolygonBezier( sal_uLong nPoly, const sal_uLong* pPoints, + const SalPoint* const* pPtAry, const sal_uInt8* const* pFlgAry ); + virtual bool drawPolyLine( const ::basegfx::B2DPolygon&, double fTransparency, + const ::basegfx::B2DVector& rLineWidths, basegfx::B2DLineJoin ); // CopyArea --> No RasterOp, but ClipRegion - virtual void copyArea( long nDestX, long nDestY, long nSrcX, long nSrcY, long nSrcWidth, - long nSrcHeight, sal_uInt16 nFlags ); + virtual void copyArea( long nDestX, long nDestY, long nSrcX, long nSrcY, long nSrcWidth, + long nSrcHeight, sal_uInt16 nFlags ); // CopyBits and DrawBitmap --> RasterOp and ClipRegion // CopyBits() --> pSrcGraphics == NULL, then CopyBits on same Graphics - virtual void copyBits( const SalTwoRect* pPosAry, SalGraphics* pSrcGraphics ); - virtual void drawBitmap( const SalTwoRect* pPosAry, const SalBitmap& rSalBitmap ); - virtual void drawBitmap( const SalTwoRect* pPosAry, - const SalBitmap& rSalBitmap, - SalColor nTransparentColor ); - virtual void drawBitmap( const SalTwoRect* pPosAry, - const SalBitmap& rSalBitmap, - const SalBitmap& rTransparentBitmap ); - virtual void drawMask( const SalTwoRect* pPosAry, - const SalBitmap& rSalBitmap, - SalColor nMaskColor ); - - virtual SalBitmap* getBitmap( long nX, long nY, long nWidth, long nHeight ); - virtual SalColor getPixel( long nX, long nY ); + virtual void copyBits( const SalTwoRect* pPosAry, SalGraphics* pSrcGraphics ); + virtual void drawBitmap( const SalTwoRect* pPosAry, const SalBitmap& rSalBitmap ); + virtual void drawBitmap( const SalTwoRect* pPosAry, + const SalBitmap& rSalBitmap, + SalColor nTransparentColor ); + virtual void drawBitmap( const SalTwoRect* pPosAry, + const SalBitmap& rSalBitmap, + const SalBitmap& rTransparentBitmap ); + virtual void drawMask( const SalTwoRect* pPosAry, + const SalBitmap& rSalBitmap, + SalColor nMaskColor ); + + virtual SalBitmap* getBitmap( long nX, long nY, long nWidth, long nHeight ); + virtual SalColor getPixel( long nX, long nY ); // invert --> ClipRegion (only Windows or VirDevs) - virtual void invert( long nX, long nY, long nWidth, long nHeight, SalInvert nFlags); - virtual void invert( sal_uLong nPoints, const SalPoint* pPtAry, SalInvert nFlags ); + virtual void invert( long nX, long nY, long nWidth, long nHeight, SalInvert nFlags); + virtual void invert( sal_uLong nPoints, const SalPoint* pPtAry, SalInvert nFlags ); - virtual sal_Bool drawEPS( long nX, long nY, long nWidth, long nHeight, void* pPtr, sal_uLong nSize ); + virtual sal_Bool drawEPS( long nX, long nY, long nWidth, long nHeight, void* pPtr, sal_uLong nSize ); - virtual bool drawAlphaBitmap( const SalTwoRect&, - const SalBitmap& rSourceBitmap, - const SalBitmap& rAlphaBitmap ); + virtual bool drawAlphaBitmap( const SalTwoRect&, + const SalBitmap& rSourceBitmap, + const SalBitmap& rAlphaBitmap ); - virtual bool drawAlphaRect( long nX, long nY, long nWidth, - long nHeight, sal_uInt8 nTransparency ); + virtual bool drawAlphaRect( long nX, long nY, long nWidth, + long nHeight, sal_uInt8 nTransparency ); - CGPoint* makeCGptArray(sal_uLong nPoints, const SalPoint* pPtAry); + CGPoint* makeCGptArray(sal_uLong nPoints, const SalPoint* pPtAry); // native widget rendering methods that require mirroring - virtual sal_Bool hitTestNativeControl( ControlType nType, ControlPart nPart, const Rectangle& rControlRegion, - const Point& aPos, sal_Bool& rIsInside ); - virtual sal_Bool drawNativeControl( ControlType nType, ControlPart nPart, const Rectangle& rControlRegion, - ControlState nState, const ImplControlValue& aValue, - const rtl::OUString& aCaption ); - virtual sal_Bool getNativeControlRegion( ControlType nType, ControlPart nPart, const Rectangle& rControlRegion, ControlState nState, - const ImplControlValue& aValue, const rtl::OUString& aCaption, - Rectangle &rNativeBoundingRegion, Rectangle &rNativeContentRegion ); + virtual sal_Bool hitTestNativeControl( ControlType nType, ControlPart nPart, const Rectangle& rControlRegion, + const Point& aPos, sal_Bool& rIsInside ); + virtual sal_Bool drawNativeControl( ControlType nType, ControlPart nPart, const Rectangle& rControlRegion, + ControlState nState, const ImplControlValue& aValue, + const rtl::OUString& aCaption ); + virtual sal_Bool getNativeControlRegion( ControlType nType, ControlPart nPart, const Rectangle& rControlRegion, + ControlState nState, const ImplControlValue& aValue, + const rtl::OUString& aCaption, + Rectangle &rNativeBoundingRegion, + Rectangle &rNativeContentRegion ); // get device resolution - virtual void GetResolution( long& rDPIX, long& rDPIY ); + virtual void GetResolution( long& rDPIX, long& rDPIY ); // get the depth of the device - virtual sal_uInt16 GetBitCount() const; + virtual sal_uInt16 GetBitCount() const; // get the width of the device - virtual long GetGraphicsWidth() const; + virtual long GetGraphicsWidth() const; // set the clip region to empty - virtual void ResetClipRegion(); + virtual void ResetClipRegion(); // set the line color to transparent (= don't draw lines) - virtual void SetLineColor(); + virtual void SetLineColor(); // set the line color to a specific color - virtual void SetLineColor( SalColor nSalColor ); + virtual void SetLineColor( SalColor nSalColor ); // set the fill color to transparent (= don't fill) - virtual void SetFillColor(); + virtual void SetFillColor(); // set the fill color to a specific color, shapes will be // filled accordingly - virtual void SetFillColor( SalColor nSalColor ); + virtual void SetFillColor( SalColor nSalColor ); // enable/disable XOR drawing - virtual void SetXORMode( bool bSet, bool bInvertOnly ); + virtual void SetXORMode( bool bSet, bool bInvertOnly ); // set line color for raster operations - virtual void SetROPLineColor( SalROPColor nROPColor ); + virtual void SetROPLineColor( SalROPColor nROPColor ); // set fill color for raster operations - virtual void SetROPFillColor( SalROPColor nROPColor ); + virtual void SetROPFillColor( SalROPColor nROPColor ); // set the text color to a specific color - virtual void SetTextColor( SalColor nSalColor ); + virtual void SetTextColor( SalColor nSalColor ); // set the font - virtual sal_uInt16 SetFont( FontSelectPattern*, int nFallbackLevel ); + virtual sal_uInt16 SetFont( FontSelectPattern*, int nFallbackLevel ); // get the current font's etrics - virtual void GetFontMetric( ImplFontMetricData*, int nFallbackLevel ); + virtual void GetFontMetric( ImplFontMetricData*, int nFallbackLevel ); // get kernign pairs of the current font // return only PairCount if (pKernPairs == NULL) - virtual sal_uLong GetKernPairs( sal_uLong nPairs, ImplKernPairData* pKernPairs ); + virtual sal_uLong GetKernPairs( sal_uLong nPairs, ImplKernPairData* pKernPairs ); // get the repertoire of the current font virtual const ImplFontCharMap* GetImplFontCharMap() const; virtual bool GetImplFontCapabilities(vcl::FontCapabilities &rFontCapabilities) const; // graphics must fill supplied font list - virtual void GetDevFontList( ImplDevFontList* ); + virtual void GetDevFontList( ImplDevFontList* ); // graphics should call ImplAddDevFontSubstitute on supplied // OutputDevice for all its device specific preferred font substitutions - virtual void GetDevFontSubstList( OutputDevice* ); - virtual bool AddTempDevFont( ImplDevFontList*, const rtl::OUString& rFileURL, const rtl::OUString& rFontName ); + virtual void GetDevFontSubstList( OutputDevice* ); + virtual bool AddTempDevFont( ImplDevFontList*, const rtl::OUString& rFileURL, + const rtl::OUString& rFontName ); // CreateFontSubset: a method to get a subset of glyhps of a font // inside a new valid font file // returns TRUE if creation of subset was successfull @@ -294,14 +238,13 @@ public: // rInfo: additional outgoing information // implementation note: encoding 0 with glyph id 0 should be added implicitly // as "undefined character" - virtual sal_Bool CreateFontSubset( const rtl::OUString& rToFile, - const ImplFontData* pFont, - long* pGlyphIDs, - sal_uInt8* pEncoding, - sal_Int32* pWidths, - int nGlyphs, - FontSubsetInfo& rInfo // out parameter - ); + virtual sal_Bool CreateFontSubset( const rtl::OUString& rToFile, + const ImplFontData* pFont, + long* pGlyphIDs, + sal_uInt8* pEncoding, + sal_Int32* pWidths, + int nGlyphs, + FontSubsetInfo& rInfo); // GetFontEncodingVector: a method to get the encoding map Unicode // to font encoded character; this is only used for type1 fonts and @@ -325,84 +268,45 @@ public: FontSubsetInfo& rInfo, long* pDataLen ); // frees the font data again - virtual void FreeEmbedFontData( const void* pData, long nDataLen ); + virtual void FreeEmbedFontData( const void* pData, long nDataLen ); - virtual void GetGlyphWidths( const ImplFontData*, - bool bVertical, - Int32Vector& rWidths, - Ucs2UIntMap& rUnicodeEnc ); + virtual void GetGlyphWidths( const ImplFontData*, + bool bVertical, + Int32Vector& rWidths, + Ucs2UIntMap& rUnicodeEnc ); - virtual sal_Bool GetGlyphBoundRect( sal_GlyphId nIndex, Rectangle& ); - virtual sal_Bool GetGlyphOutline( sal_GlyphId nIndex, basegfx::B2DPolyPolygon& ); + virtual sal_Bool GetGlyphBoundRect( sal_GlyphId nIndex, Rectangle& ); + virtual sal_Bool GetGlyphOutline( sal_GlyphId nIndex, basegfx::B2DPolyPolygon& ); - virtual SalLayout* GetTextLayout( ImplLayoutArgs&, int nFallbackLevel ); - virtual void DrawServerFontLayout( const ServerFontLayout& ); - virtual bool supportsOperation( OutDevSupportType ) const; + virtual SalLayout* GetTextLayout( ImplLayoutArgs&, int nFallbackLevel ); + virtual void DrawServerFontLayout( const ServerFontLayout& ); + virtual bool supportsOperation( OutDevSupportType ) const; // Query the platform layer for control support virtual sal_Bool IsNativeControlSupported( ControlType nType, ControlPart nPart ); - virtual SystemGraphicsData GetGraphicsData() const; - virtual SystemFontData GetSysFontData( int /* nFallbacklevel */ ) const; + virtual SystemGraphicsData GetGraphicsData() const; + virtual SystemFontData GetSysFontData( int /* nFallbacklevel */ ) const; private: // differences between VCL, Quartz and kHiThemeOrientation coordinate systems // make some graphics seem to be vertically-mirrored from a VCL perspective - bool IsFlipped() const { return mbWindow; } + bool IsFlipped() const { return mbWindow; }; void ApplyXorContext(); void Pattern50Fill(); UInt32 getState( ControlState nState ); UInt32 getTrackState( ControlState nState ); + bool GetRawFontData( const ImplFontData* pFontData, + std::vector<unsigned char>& rBuffer, + bool* pJustCFF ); }; -class XorEmulation -{ -public: - XorEmulation(); - /*final*/ ~XorEmulation(); - - void SetTarget( int nWidth, int nHeight, int nBitmapDepth, CGContextRef, CGLayerRef ); - bool UpdateTarget(); - void Enable() { mbIsEnabled = true; } - void Disable() { mbIsEnabled = false; } - bool IsEnabled() const { return mbIsEnabled; } - CGContextRef GetTargetContext() const { return mxTargetContext; } - CGContextRef GetMaskContext() const { return (mbIsEnabled ? mxMaskContext : NULL); } - -private: - CGLayerRef mxTargetLayer; - CGContextRef mxTargetContext; - CGContextRef mxMaskContext; - CGContextRef mxTempContext; - sal_uLong* mpMaskBuffer; - sal_uLong* mpTempBuffer; - int mnBufferLongs; - bool mbIsEnabled; -}; - - -// --- some trivial inlines - inline void IosSalGraphics::RefreshRect( const CGRect& rRect ) { RefreshRect( rRect.origin.x, rRect.origin.y, rRect.size.width, rRect.size.height ); } -inline RGBAColor::RGBAColor( SalColor nSalColor ) -: mfRed( SALCOLOR_RED(nSalColor) * (1.0/255)) -, mfGreen( SALCOLOR_GREEN(nSalColor) * (1.0/255)) -, mfBlue( SALCOLOR_BLUE(nSalColor) * (1.0/255)) -, mfAlpha( 1.0 ) // opaque -{} - -inline RGBAColor::RGBAColor( float fRed, float fGreen, float fBlue, float fAlpha ) -: mfRed( fRed ) -, mfGreen( fGreen ) -, mfBlue( fBlue ) -, mfAlpha( fAlpha ) -{} - -#endif // _SV_SALGDI_H +#endif // _VCL_IOS_SALGDI_H /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/ios/salgdicommon.hxx b/vcl/inc/ios/salgdicommon.hxx new file mode 100644 index 000000000000..795fe501ae6c --- /dev/null +++ b/vcl/inc/ios/salgdicommon.hxx @@ -0,0 +1,84 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _VCL_IOS_SALGDICOMMON_H +#define _VCL_IOS_SALGDICOMMON_H + +// abstracting quartz color instead of having to use an CGFloat[] array +class RGBAColor +{ +public: + RGBAColor( SalColor ); + RGBAColor( float fRed, float fGreen, float fBlue, float fAlpha ); //NOTUSEDYET + const float* AsArray() const { return &m_fRed; } + bool IsVisible() const { return m_fAlpha > 0; } + void SetAlpha( float fAlpha ) { m_fAlpha = fAlpha; } +private: + float m_fRed, m_fGreen, m_fBlue, m_fAlpha; +}; + +inline RGBAColor::RGBAColor( SalColor nSalColor ) +: m_fRed( SALCOLOR_RED(nSalColor) * (1.0/255)) +, m_fGreen( SALCOLOR_GREEN(nSalColor) * (1.0/255)) +, m_fBlue( SALCOLOR_BLUE(nSalColor) * (1.0/255)) +, m_fAlpha( 1.0 ) // opaque +{} + +inline RGBAColor::RGBAColor( float fRed, float fGreen, float fBlue, float fAlpha ) +: m_fRed( fRed ) +, m_fGreen( fGreen ) +, m_fBlue( fBlue ) +, m_fAlpha( fAlpha ) +{} + +class XorEmulation +{ +public: + XorEmulation(); + ~XorEmulation(); + + void SetTarget( int nWidth, int nHeight, int nBitmapDepth, CGContextRef, CGLayerRef ); + bool UpdateTarget(); + void Enable() { m_bIsEnabled = true; } + void Disable() { m_bIsEnabled = false; } + bool IsEnabled() const { return m_bIsEnabled; } + CGContextRef GetTargetContext() const { return m_xTargetContext; } + CGContextRef GetMaskContext() const { return (m_bIsEnabled ? m_xMaskContext : NULL); } + +private: + CGLayerRef m_xTargetLayer; + CGContextRef m_xTargetContext; + CGContextRef m_xMaskContext; + CGContextRef m_xTempContext; + sal_uLong* m_pMaskBuffer; + sal_uLong* m_pTempBuffer; + int m_nBufferLongs; + bool m_bIsEnabled; +}; + +#endif /* _VCL_IOS_SALGDICOMMON_H */ diff --git a/vcl/inc/vcl/sysdata.hxx b/vcl/inc/vcl/sysdata.hxx index 4e4e71f2ac4b..81195b1de4d6 100644 --- a/vcl/inc/vcl/sysdata.hxx +++ b/vcl/inc/vcl/sysdata.hxx @@ -203,7 +203,7 @@ struct SystemFontData #elif defined( QUARTZ ) void* aATSUFontID; // native font object #elif defined( IOS ) - CGFontRef rFont; // native font object + void* rCTFont; // native font object #elif defined( UNX ) void* nFontId; // native font id int nFontFlags; // native font flags diff --git a/vcl/ios/source/gdi/salcoretextfontutils.cxx b/vcl/ios/source/gdi/salcoretextfontutils.cxx index 388d497d0aa8..2d88c8d1f017 100644 --- a/vcl/ios/source/gdi/salcoretextfontutils.cxx +++ b/vcl/ios/source/gdi/salcoretextfontutils.cxx @@ -26,74 +26,595 @@ * ************************************************************************/ -#include <boost/assert.hpp> -#include <vector> -#include <set> +#include "ios/common.h" -#include "vcl/svapp.hxx" - -#include "ios/salgdi.h" -#include "ios/saldata.hxx" #include "ios/salcoretextfontutils.hxx" +#include "ios/salgdi.h" + +#include "sft.hxx" +#include "ios/salinst.h" + + +static bool GetDevFontAttributes( CTFontDescriptorRef font_descriptor, ImplDevFontAttributes& rDFA ) +{ + + // reset the attributes + rDFA.meFamily = FAMILY_DONTKNOW; + rDFA.mePitch = PITCH_VARIABLE; + rDFA.meWidthType = WIDTH_NORMAL; + rDFA.meWeight = WEIGHT_NORMAL; + rDFA.meItalic = ITALIC_NONE; + rDFA.mbSymbolFlag = false; + rDFA.mbOrientation = true; + rDFA.mbDevice = true; + rDFA.mnQuality = 0; + + CFNumberRef format = (CFNumberRef)CTFontDescriptorCopyAttribute(font_descriptor, kCTFontFormatAttribute); + int value = 0; + CFNumberGetValue(format, kCFNumberIntType, &value); + CFRelease(format); + + if (value == kCTFontFormatBitmap) + { + /* we don't want bitmap fonts */ + return false; + } + rDFA.mbSubsettable = true; + rDFA.mbEmbeddable = false; + + CFStringRef family_name = (CFStringRef)CTFontDescriptorCopyAttribute(font_descriptor, kCTFontFamilyNameAttribute); + rDFA.maName = GetOUString(family_name); + CFRelease(family_name); + + CFDictionaryRef traits = (CFDictionaryRef)CTFontDescriptorCopyAttribute(font_descriptor, kCTFontTraitsAttribute); + CFNumberRef symbolics = (CFNumberRef)CFDictionaryGetValue(traits, kCTFontSymbolicTrait); + + value = 0; + CFNumberGetValue(symbolics, kCFNumberIntType, &value); + CFRelease(symbolics); + + if (value & kCTFontMonoSpaceTrait) + { + rDFA.mePitch = PITCH_FIXED; + } + + if (value & kCTFontItalicTrait) + { + rDFA.meItalic = ITALIC_NORMAL; + } + + if (value & kCTFontBoldTrait) + { + rDFA.meWeight = WEIGHT_BOLD; + } + + if (value & kCTFontCondensedTrait) + { + rDFA.meWidthType = WIDTH_CONDENSED; + } + else if (value & kCTFontExpandedTrait) + { + rDFA.meWidthType = WIDTH_EXPANDED; + } + switch(value & kCTFontClassMaskTrait) + { + case kCTFontOldStyleSerifsClass: + rDFA.meFamily = FAMILY_ROMAN; + break; + case kCTFontTransitionalSerifsClass: + case kCTFontModernSerifsClass: + case kCTFontClarendonSerifsClass: + case kCTFontSlabSerifsClass: + case kCTFontFreeformSerifsClass: + break; + case kCTFontSansSerifClass: + rDFA.meFamily = FAMILY_SWISS; + case kCTFontOrnamentalsClass: + rDFA.meFamily = FAMILY_DECORATIVE; + break; + case kCTFontScriptsClass: + rDFA.meFamily = FAMILY_SCRIPT; + break; + case kCTFontSymbolicClass: + rDFA.mbSymbolFlag = true; + break; + } + + CFNumberRef weight = (CFNumberRef)CFDictionaryGetValue(traits, kCTFontWeightTrait); + float fdval = 0.0; + CFNumberGetValue(weight, kCFNumberFloatType, &fdval); + if (fdval > 0.6) + { + rDFA.meWeight = WEIGHT_BLACK; + } + else if (fdval > 0.4) + { + rDFA.meWeight = WEIGHT_ULTRABOLD; + } + else if (fdval > 0.3) + { + rDFA.meWeight = WEIGHT_BOLD; + } + else if (fdval > 0.0) + { + rDFA.meWeight = WEIGHT_SEMIBOLD; + } + else if (fdval <= -0.8) + { + rDFA.meWeight = WEIGHT_ULTRALIGHT; + } + else if (fdval <= -0.4) + { + rDFA.meWeight = WEIGHT_LIGHT; + } + else if (fdval <= -0.3) + { + rDFA.meWeight = WEIGHT_SEMILIGHT; + } + else if (fdval <= -0.2) + { + rDFA.meWeight = WEIGHT_THIN; + } + else + { + rDFA.meWeight = WEIGHT_NORMAL; + } + + CFStringRef string_ref = (CFStringRef)CTFontDescriptorCopyAttribute(font_descriptor, kCTFontStyleNameAttribute); + rtl::OUString font_name = GetOUString(string_ref); + rtl::OUString font_name_lc(font_name.toAsciiLowerCase()); + CFRelease(string_ref); + + // heuristics to adjust font slant + if ( (font_name_lc.indexOf("oblique") != -1) || + (font_name_lc.indexOf("inclined") != -1) || + (font_name_lc.indexOf("slanted") != -1) ) + { + rDFA.meItalic = ITALIC_OBLIQUE; + } + + // heuristics to adjust font width + if (font_name_lc.indexOf("narrow") != -1) + { + rDFA.meWidthType = WIDTH_SEMI_CONDENSED; + } + + // heuristics for font family type + if ( (font_name_lc.indexOf("script") != -1) || + (font_name_lc.indexOf("chancery") != -1) || + (font_name_lc.indexOf("zapfino") != -1)) + { + rDFA.meFamily = FAMILY_SCRIPT; + } + else if ( (font_name_lc.indexOf("comic") != -1) || + (font_name_lc.indexOf("outline") != -1) || + (font_name_lc.indexOf("pinpoint") != -1) ) + { + rDFA.meFamily = FAMILY_DECORATIVE; + } + else if ( (font_name_lc.indexOf("sans") != -1) || + (font_name_lc.indexOf("arial") != -1) ) + { + rDFA.meFamily = FAMILY_SWISS; + } + else if ( (font_name_lc.indexOf("roman") != -1) || + (font_name_lc.indexOf("times") != -1) ) + { + rDFA.meFamily = FAMILY_ROMAN; + } + return true; +} SystemFontList::SystemFontList() { + CTFontCollectionRef font_collection = CTFontCollectionCreateFromAvailableFonts(NULL); + if (font_collection) + { + CFArrayRef font_descriptors = CTFontCollectionCreateMatchingFontDescriptors(font_collection); + + for(int i = 0; i < CFArrayGetCount(font_descriptors); i++) + { + CTFontDescriptorRef font_descriptor = (CTFontDescriptorRef)CFArrayGetValueAtIndex(font_descriptors, i); + CTFontRef font = CTFontCreateWithFontDescriptor(font_descriptor, 0, NULL); + ImplDevFontAttributes devfont_attr; + if (GetDevFontAttributes( font_descriptor, devfont_attr ) ) + { + ImplCoreTextFontData* font_data = new ImplCoreTextFontData(devfont_attr, font); + if (font_data && font_data->GetCTFont()) + { + m_aFontContainer [ font_data->GetCTFont() ] = font_data; + } + } + CFRelease(font); + } + CFRelease(font_descriptors); + } + CFRelease(font_collection); } SystemFontList::~SystemFontList() { + CoreTextFontContainer::const_iterator it = m_aFontContainer.begin(); + for(; it != m_aFontContainer.end(); ++it ) + delete (*it).second; + m_aFontContainer.clear(); } +ImplCoreTextFontData* SystemFontList::GetFontDataFromRef( CTFontRef font ) const +{ + CoreTextFontContainer::const_iterator it = m_aFontContainer.find( font ); + return it == m_aFontContainer.end() ? NULL : (*it).second; +} + + void SystemFontList::AnnounceFonts( ImplDevFontList& rFontList ) const { - (void) rFontList; + CoreTextFontContainer::const_iterator it = m_aFontContainer.begin(); + for(; it != m_aFontContainer.end(); ++it ) + { + rFontList.Add( (*it).second->Clone() ); + } +} - // Implement... +ImplCoreTextFontData::ImplCoreTextFontData( const ImplDevFontAttributes& rDFA, CTFontRef font ) +: ImplFontData( rDFA, 0 ) +, m_CTFontRef((CTFontRef)CFRetain(font)) +, m_pCharMap( NULL ) +, m_bHasOs2Table( false ) +, m_bOs2TableRead( false ) +, m_bCmapTableRead( false ) +, m_bHasCJKSupport( false ) +, m_bFontCapabilitiesRead( false ) +{ } -// not all fonts are suitable for glyph fallback => sort them -struct GfbCompare{ bool operator()(const ImplIosFontData*, const ImplIosFontData*); }; +ImplCoreTextFontData::~ImplCoreTextFontData() +{ + if ( m_pCharMap ) + { + m_pCharMap->DeReference(); + } + if ( m_CTFontRef ) + { + CFRelease(m_CTFontRef); + } +} + +ImplFontData* ImplCoreTextFontData::Clone() const +{ + ImplCoreTextFontData* pClone = new ImplCoreTextFontData(*this); + if ( m_pCharMap ) + { + m_pCharMap->AddReference(); + } + if ( m_CTFontRef ) + { + pClone->m_CTFontRef = (CTFontRef)CFRetain(m_CTFontRef); + } + return pClone; +} + +ImplFontEntry* ImplCoreTextFontData::CreateFontInstance(FontSelectPattern& rFSD) const +{ + return new ImplFontEntry(rFSD); +} + +const ImplFontCharMap* ImplCoreTextFontData::GetImplFontCharMap() +{ + // return the cached charmap + if ( m_pCharMap ) + { + return m_pCharMap; + } + // set the default charmap + m_pCharMap = ImplFontCharMap::GetDefaultMap(); + m_pCharMap->AddReference(); + + // get the CMAP byte size + CFDataRef rCmapTable = CTFontCopyTable( m_CTFontRef, kCTFontTableCmap, kCTFontTableOptionNoOptions); + if (!rCmapTable) + { + return m_pCharMap; + } + if (!m_bCmapTableRead) + { + m_bCmapTableRead = true; + DetermineCJKSupport_cmap(rCmapTable); + } + // parse the CMAP + CmapResult aCmapResult; + if (ParseCMAP( CFDataGetBytePtr(rCmapTable), CFDataGetLength(rCmapTable), aCmapResult ) ) + { + m_pCharMap = new ImplFontCharMap( aCmapResult ); + m_pCharMap->AddReference(); + } + CFRelease(rCmapTable); + return m_pCharMap; +} + +bool ImplCoreTextFontData::GetImplFontCapabilities(vcl::FontCapabilities &rFontCapabilities) +{ + // read this only once per font + if ( m_bFontCapabilitiesRead ) + { + rFontCapabilities = m_aFontCapabilities; + return !rFontCapabilities.maUnicodeRange.empty() || !rFontCapabilities.maCodePageRange.empty(); + } + m_bFontCapabilitiesRead = true; + + // get the GSUB table raw data + CFDataRef rGSUBTable = CTFontCopyTable( m_CTFontRef, kCTFontTableGSUB, kCTFontTableOptionNoOptions); + if (rGSUBTable) + { + + vcl::getTTScripts(m_aFontCapabilities.maGSUBScriptTags, + CFDataGetBytePtr(rGSUBTable), CFDataGetLength(rGSUBTable)); + CFRelease(rGSUBTable); + } + CFDataRef OS2_Table = CTFontCopyTable( m_CTFontRef, kCTFontTableOS2, kCTFontTableOptionNoOptions); + if (OS2_Table) + { + vcl::getTTCoverage( + m_aFontCapabilities.maUnicodeRange, + m_aFontCapabilities.maCodePageRange, + CFDataGetBytePtr(OS2_Table), CFDataGetLength(OS2_Table)); + /* while we are at it let's solve HasCJK for the same price */ + if (!m_bOs2TableRead ) + { + m_bOs2TableRead = true; + m_bHasOs2Table = true; + DetermineCJKSupport_OS2(OS2_Table); + } + CFRelease(OS2_Table); + } + rFontCapabilities = m_aFontCapabilities; + return !rFontCapabilities.maUnicodeRange.empty() || !rFontCapabilities.maCodePageRange.empty(); +} + +struct font_table +{ + unsigned char* table; + unsigned char* dir_entry; + unsigned char* cursor; +}; + +void addTable(struct font_table* table, CTFontTableTag tag, CFDataRef data) +{ + if (data && CFDataGetLength(data) > 0) + { + *(uint32_t*)table->dir_entry = CFSwapInt32HostToBig(tag); + table->dir_entry += 4; + *(uint32_t*)table->dir_entry = 0; /* TODO: checksum */ + table->dir_entry += 4; + *(uint32_t*)table->dir_entry = CFSwapInt32HostToBig((uint32_t)((uintptr_t)table->cursor - (uintptr_t)table)); + table->dir_entry += 4; + *(uint32_t*)table->dir_entry = CFSwapInt32HostToBig(CFDataGetLength(data)); + table->dir_entry += 4; + + memcpy(table->cursor, CFDataGetBytePtr(data), CFDataGetLength(data)); + table->cursor += CFDataGetLength(data); + } +} + +bool ImplCoreTextFontData::GetRawFontData( std::vector<unsigned char>& rBuffer, bool* pJustCFF ) const +{ + bool rc; + int table_count = 0; + + CFDataRef CFF_table = CTFontCopyTable( m_CTFontRef, kCTFontTableCFF, kCTFontTableOptionNoOptions); + if (pJustCFF) + { + if (CFF_table) + { + *pJustCFF = CFDataGetLength(CFF_table) ? true : false; + } + if (CFF_table) + { + CFRelease(CFF_table); + return true; + } + else + { + return false; + } + } + size_t total_len = 0; + CFDataRef head_table = CTFontCopyTable( m_CTFontRef, kCTFontTableHead, kCTFontTableOptionNoOptions); + CFDataRef maxp_table = CTFontCopyTable( m_CTFontRef, kCTFontTableMaxp, kCTFontTableOptionNoOptions); + CFDataRef cmap_table = CTFontCopyTable( m_CTFontRef, kCTFontTableHead, kCTFontTableOptionNoOptions); + CFDataRef name_table = CTFontCopyTable( m_CTFontRef, kCTFontTableName, kCTFontTableOptionNoOptions); + CFDataRef hhea_table = CTFontCopyTable( m_CTFontRef, kCTFontTableHhea, kCTFontTableOptionNoOptions); + CFDataRef hmtx_table = CTFontCopyTable( m_CTFontRef, kCTFontTableHmtx, kCTFontTableOptionNoOptions); + rc = false; + if (head_table && maxp_table && cmap_table && name_table && hhea_table && hmtx_table) + { + if (CFDataGetLength(head_table) && + CFDataGetLength(maxp_table) && + CFDataGetLength(name_table) && + CFDataGetLength(hhea_table) && + CFDataGetLength(hmtx_table)) + { + table_count += 6; + total_len = CFDataGetLength(head_table) + + CFDataGetLength(maxp_table) + + CFDataGetLength(name_table) + + CFDataGetLength(hhea_table) + + CFDataGetLength(hmtx_table); + rc = true; + } + } + + CFDataRef loca_table = NULL; + CFDataRef glyf_table = NULL; + CFDataRef prep_table = NULL; + CFDataRef cvt_table = NULL; + CFDataRef fpgm_table = NULL; + if (rc) + { + if (!CFF_table || CFDataGetLength(CFF_table) == 0) + { + loca_table = CTFontCopyTable( m_CTFontRef, kCTFontTableLoca, kCTFontTableOptionNoOptions); + glyf_table = CTFontCopyTable( m_CTFontRef, kCTFontTableGlyf, kCTFontTableOptionNoOptions); + if (!loca_table || !glyf_table || !CFDataGetLength(loca_table) || !CFDataGetLength(glyf_table)) + { + rc = false; + } + else + { + table_count += 2; + total_len += CFDataGetLength(loca_table) + CFDataGetLength(glyf_table); + prep_table = CTFontCopyTable( m_CTFontRef, kCTFontTablePrep, kCTFontTableOptionNoOptions); + cvt_table = CTFontCopyTable( m_CTFontRef, kCTFontTableCvt, kCTFontTableOptionNoOptions); + fpgm_table = CTFontCopyTable( m_CTFontRef, kCTFontTableFpgm, kCTFontTableOptionNoOptions); + if (prep_table || CFDataGetLength(prep_table) > 0) + { + table_count += 1; + total_len += CFDataGetLength(prep_table); + } + if (cvt_table || CFDataGetLength(cvt_table) > 0) + { + table_count += 1; + total_len += CFDataGetLength(cvt_table); + } + if (fpgm_table || CFDataGetLength(fpgm_table) > 0) + { + table_count += 1; + total_len += CFDataGetLength(fpgm_table); + } + } + } + else + { + table_count += 1; + total_len += CFDataGetLength(CFF_table); + } + } + if (rc) + { + total_len += 12 + 16 * table_count; + rBuffer.resize(total_len); + struct font_table table; + unsigned char* cursor = &rBuffer[0]; + int nLog2 = 0; + + while( (table_count >> nLog2) > 1 ) ++nLog2; + + table.table = cursor; + *(uint16_t*)cursor = CFSwapInt16HostToBig(1); + cursor += 2; + *(uint16_t*)cursor = 0; + cursor += 2; + *(uint16_t*)cursor = CFSwapInt16HostToBig(table_count); + cursor += 2; + *(uint16_t*)cursor = CFSwapInt16HostToBig(nLog2 * 16); + cursor += 2; + *(uint16_t*)cursor = CFSwapInt16HostToBig(nLog2); + cursor += 2; + *(uint16_t*)cursor = CFSwapInt16HostToBig((table_count - nLog2) * 16); // rangeShift + cursor += 2; + table.dir_entry = cursor; + cursor += (16 * table_count); + table.cursor = cursor; + addTable(&table, kCTFontTableCmap, cmap_table); + addTable(&table, kCTFontTableCvt, cvt_table); + addTable(&table, kCTFontTableFpgm, fpgm_table); + addTable(&table, kCTFontTableCFF, CFF_table); + addTable(&table, kCTFontTableGlyf, glyf_table); + addTable(&table, kCTFontTableLoca, loca_table); + addTable(&table, kCTFontTableHead, head_table); + addTable(&table, kCTFontTableHhea, hhea_table); + addTable(&table, kCTFontTableHmtx, hmtx_table); + addTable(&table, kCTFontTableMaxp, maxp_table); + addTable(&table, kCTFontTableName, name_table); + addTable(&table, kCTFontTablePrep, prep_table); + } + SafeCFRelease(cmap_table); + SafeCFRelease(cvt_table); + SafeCFRelease(fpgm_table); + SafeCFRelease(CFF_table); + SafeCFRelease(glyf_table); + SafeCFRelease(loca_table); + SafeCFRelease(head_table); + SafeCFRelease(hhea_table); + SafeCFRelease(hmtx_table); + SafeCFRelease(maxp_table); + SafeCFRelease(name_table); + SafeCFRelease(prep_table); + + return rc; +} -inline bool GfbCompare::operator()( const ImplIosFontData* pA, const ImplIosFontData* pB ) +void ImplCoreTextFontData::DetermineCJKSupport_OS2(CFDataRef rOS2Table) { - // use symbol fonts only as last resort - bool bPreferA = !pA->IsSymbolFont(); - bool bPreferB = !pB->IsSymbolFont(); - if( bPreferA != bPreferB ) - return bPreferA; - // prefer scalable fonts - bPreferA = pA->IsScalable(); - bPreferB = pB->IsScalable(); - if( bPreferA != bPreferB ) - return bPreferA; - // prefer non-slanted fonts - bPreferA = (pA->GetSlant() == ITALIC_NONE); - bPreferB = (pB->GetSlant() == ITALIC_NONE); - if( bPreferA != bPreferB ) - return bPreferA; - // prefer normal weight fonts - bPreferA = (pA->GetWeight() == WEIGHT_NORMAL); - bPreferB = (pB->GetWeight() == WEIGHT_NORMAL); - if( bPreferA != bPreferB ) - return bPreferA; - // prefer normal width fonts - bPreferA = (pA->GetWidthType() == WIDTH_NORMAL); - bPreferB = (pB->GetWidthType() == WIDTH_NORMAL); - if( bPreferA != bPreferB ) - return bPreferA; - return false; + if (CFDataGetLength(rOS2Table) >= 48) + { + const unsigned short* pOS2buffer = (const unsigned short*)CFDataGetBytePtr(rOS2Table); + const unsigned short version = CFSwapInt16BigToHost(pOS2buffer[0]); + if ( version >= 1) + { + const unsigned short unicode_range = CFSwapInt16BigToHost(pOS2buffer[23]); + if ( unicode_range & 0x2DF0) + { + m_bHasCJKSupport = true; + } + } + } } -void SystemFontList::InitGlyphFallbacks() +void ImplCoreTextFontData::DetermineCJKSupport_cmap(CFDataRef rCmapTable) { + int table_len = CFDataGetLength(rCmapTable) / 2; + if (table_len >= 12) + { + const unsigned short* pCmap = (const unsigned short*)CFDataGetBytePtr(rCmapTable); + if (pCmap[0] == 0) + { + short nb_sub_tables = CFSwapInt16BigToHost(pCmap[1]); + for(int i = 2; --nb_sub_tables >= 0 && i < table_len; i += 4) + { + short platform = CFSwapInt16BigToHost(pCmap[i]); + if ( platform == kFontMacintoshPlatform ) + { + short encoding = CFSwapInt16BigToHost(pCmap[i+1]); + if ( encoding == kFontJapaneseScript || + encoding == kFontTraditionalChineseScript || + encoding == kFontKoreanScript || + encoding == kFontSimpleChineseScript ) + { + m_bHasCJKSupport = true; + break; + } + } + } + } + } } -ImplIosFontData* SystemFontList::GetFontDataFromRef( CTFontRef nFontRef ) const +bool ImplCoreTextFontData::HasCJKSupport( void ) { - IosFontContainer::const_iterator it = maFontContainer.find( nFontRef ); - if( it == maFontContainer.end() ) - return NULL; - return (*it).second; + // read this only once per font + if (!m_bOs2TableRead ) + { + m_bOs2TableRead = true; + CFDataRef rOS2Table = CTFontCopyTable( m_CTFontRef, kCTFontTableOS2, kCTFontTableOptionNoOptions); + if (rOS2Table) + { + m_bHasOs2Table = true; + DetermineCJKSupport_OS2(rOS2Table); + CFRelease(rOS2Table); + } + } + if ( !m_bCmapTableRead && !m_bHasOs2Table && !m_bHasCJKSupport ) + { + m_bCmapTableRead = true; + CFDataRef rCmapTable = CTFontCopyTable( m_CTFontRef, kCTFontTableCmap, kCTFontTableOptionNoOptions); + if (rCmapTable) + { + DetermineCJKSupport_cmap(rCmapTable); + CFRelease(rCmapTable); + } + } + return m_bHasCJKSupport; } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/ios/source/gdi/salcoretextlayout.cxx b/vcl/ios/source/gdi/salcoretextlayout.cxx index 3ff4c07a4b99..4fd1baf4afc2 100644 --- a/vcl/ios/source/gdi/salcoretextlayout.cxx +++ b/vcl/ios/source/gdi/salcoretextlayout.cxx @@ -26,296 +26,456 @@ * ************************************************************************/ -#include "tools/debug.hxx" - -#include "ios/saldata.hxx" +#include "ios/common.h" +#include "ios/salcoretextstyle.hxx" +#include "ios/salcoretextlayout.hxx" #include "ios/salgdi.h" -#include "ios/salcoretextfontutils.hxx" - -#include "sallayout.hxx" -#include "salgdi.hxx" -#include <math.h> -class CoreTextLayout : public SalLayout -{ -public: - CoreTextLayout( CTFontSymbolicTraits&, float fFontScale ); - virtual ~CoreTextLayout(); - - virtual bool LayoutText( ImplLayoutArgs& ); - virtual void AdjustLayout( ImplLayoutArgs& ); - virtual void DrawText( SalGraphics& ) const; - - virtual int GetNextGlyphs( int nLen, sal_GlyphId* pGlyphs, Point& rPos, int&, - sal_Int32* pGlyphAdvances, int* pCharIndexes ) const; - - virtual long GetTextWidth() const; - virtual long FillDXArray( long* pDXArray ) const; - virtual int GetTextBreak( long nMaxWidth, long nCharExtra, int nFactor ) const; - virtual void GetCaretPositions( int nArraySize, long* pCaretXArray ) const; - virtual bool GetGlyphOutlines( SalGraphics&, PolyPolyVector& ) const; - virtual bool GetBoundRect( SalGraphics&, Rectangle& ) const; - - const ImplFontData* GetFallbackFontData( sal_GlyphId ) const; - - virtual void InitFont() const; - virtual void MoveGlyph( int nStart, long nNewXPos ); - virtual void DropGlyph( int nStart ); - virtual void Simplify( bool bIsBase ); - -private: - // ??? - float mfFontScale; - -private: - bool InitGIA( ImplLayoutArgs* pArgs = NULL ) const; - bool GetIdealX() const; - bool GetDeltaY() const; - void InvalidateMeasurements(); - - // cached details about the resulting layout - // mutable members since these details are all lazy initialized - mutable int mnGlyphCount; // glyph count - mutable Fixed mnCachedWidth; // cached value of resulting typographical width - int mnTrailingSpaceWidth; // in Pixels - - mutable CGGlyph* mpGlyphIds; - mutable Fixed* mpCharWidths; // map relative charpos to charwidth - mutable int* mpChars2Glyphs; // map relative charpos to absolute glyphpos - mutable int* mpGlyphs2Chars; // map absolute glyphpos to absolute charpos - mutable bool* mpGlyphRTLFlags; // BiDi status for glyphs: true if RTL - mutable Fixed* mpGlyphAdvances; // contains glyph widths for the justified layout - mutable Fixed* mpGlyphOrigAdvs; // contains glyph widths for the unjustified layout - mutable Fixed* mpDeltaY; // vertical offset from the baseline - - struct SubPortion { int mnMinCharPos, mnEndCharPos; Fixed mnXOffset; }; - typedef std::vector<SubPortion> SubPortionVector; - mutable SubPortionVector maSubPortions; - - // storing details about fonts used in glyph-fallback for this layout - mutable class FallbackInfo* mpFallbackInfo; - - // x-offset relative to layout origin - // currently only used in RTL-layouts - mutable Fixed mnBaseAdv; -}; - -class FallbackInfo -{ -public: - FallbackInfo() : mnMaxLevel(0) {} - int AddFallback( CTFontRef ); - const ImplFontData* GetFallbackFontData( int nLevel ) const; - -private: - const ImplIosFontData* maFontData[ MAX_FALLBACK ]; - CTFontRef maCTFontRef[ MAX_FALLBACK ]; - int mnMaxLevel; -}; - -CoreTextLayout::CoreTextLayout( CTFontSymbolicTraits& rCoreTextStyle, float fFontScale ) -: - mfFontScale( fFontScale ), - mnGlyphCount( -1 ), - mnCachedWidth( 0 ), - mnTrailingSpaceWidth( 0 ), - mpGlyphIds( NULL ), - mpCharWidths( NULL ), - mpChars2Glyphs( NULL ), - mpGlyphs2Chars( NULL ), - mpGlyphRTLFlags( NULL ), - mpGlyphAdvances( NULL ), - mpGlyphOrigAdvs( NULL ), - mpDeltaY( NULL ), - mpFallbackInfo( NULL ), - mnBaseAdv( 0 ) +CoreTextLayout::CoreTextLayout(IosSalGraphics* graphics, CoreTextStyleInfo* style) : + m_graphics(graphics), + m_style(style), + m_glyphs_count(-1), + m_chars_count(-1), + m_chars2glyphs(NULL), + m_glyphs2chars(NULL), + m_glyphs(NULL), + m_char_widths(NULL), + m_glyph_advances(NULL), + m_glyph_positions(NULL), + m_typesetter(NULL), + m_line(NULL), + m_has_bound_rec(false), + m_base_advance(0), + m_cached_width(0.0F), + m_current_run_index(0), + m_current_glyph_index(0), + m_current_glyphrun_index(0), + m_runs(NULL) { - (void) rCoreTextStyle; } -// ----------------------------------------------------------------------- - CoreTextLayout::~CoreTextLayout() { - delete[] mpGlyphRTLFlags; - delete[] mpGlyphs2Chars; - delete[] mpChars2Glyphs; - if( mpCharWidths != mpGlyphAdvances ) - delete[] mpCharWidths; - delete[] mpGlyphIds; - delete[] mpGlyphOrigAdvs; - delete[] mpGlyphAdvances; - - delete mpFallbackInfo; + Clean(); } -bool CoreTextLayout::LayoutText( ImplLayoutArgs& rArgs ) +void CoreTextLayout::AdjustLayout( ImplLayoutArgs& /*rArgs*/ ) { - (void) rArgs; - // Implement... - return true; + msgs_debug(layout,"-->"); + msgs_debug(layout,"<--"); + /* TODO */ } -void CoreTextLayout::AdjustLayout( ImplLayoutArgs& rArgs ) +void CoreTextLayout::Clean() { - (void) rArgs; - // Implement... + msgs_debug(layout,"-->"); + if (m_glyphs) + { + delete[] m_glyphs; + m_glyphs = NULL; + } + if (m_chars2glyphs) + { + delete[] m_chars2glyphs; + m_chars2glyphs = NULL; + } + if (m_glyphs2chars) + { + delete[] m_glyphs2chars; + m_glyphs2chars = NULL; + } + if (m_char_widths) + { + delete[] m_char_widths; + m_char_widths = NULL; + } + if (m_glyph_advances) + { + delete[] m_glyph_advances; + m_glyph_advances = NULL; + } + if (m_glyph_positions) + { + delete[] m_glyph_positions; + m_glyph_positions = NULL; + } + SafeCFRelease(m_typesetter); + SafeCFRelease(m_line); + m_has_bound_rec = false; + msgs_debug(layout,"<--"); } void CoreTextLayout::DrawText( SalGraphics& rGraphics ) const { - (void) rGraphics; - // Implement... -} - -int CoreTextLayout::GetNextGlyphs( int nLen, sal_GlyphId* pGlyphIDs, Point& rPos, int& nStart, - sal_Int32* pGlyphAdvances, int* pCharIndexes ) const -{ - (void) nLen; - (void) pGlyphIDs; - (void) rPos; - (void) nStart; - (void) pGlyphAdvances; - (void) pCharIndexes; - - if( nStart < 0 ) // first glyph requested? - nStart = 0; + msgs_debug(layout,"-->"); + IosSalGraphics& gr = static_cast<IosSalGraphics&>(rGraphics); + if (m_chars_count <= 0 || !gr.CheckContext()) + { + return; + } + CGContextSaveGState( gr.mrContext ); + Point pos = GetDrawPosition(Point(0,0)); +#if 0 + msgs_debug(layout,"at pos (%ld, %ld)", pos.X(), pos.Y()); + CGContextSetTextMatrix(gr.mrContext, CGAffineTransformMakeScale(1.0, -1.0)); + CGContextSetShouldAntialias( gr.mrContext, !gr.mbNonAntialiasedText ); + CGContextSetTextPosition(gr.mrContext, pos.X(), pos.Y()); + CTLineDraw(m_line, gr.mrContext); +#else + InitGIA(); + msgs_debug(layout,"at- pos (%ld, %ld)", pos.X(), pos.Y()); + CGFontRef cg_font = CTFontCopyGraphicsFont(m_style->GetFont(), NULL); + CGContextSetFont(gr.mrContext, cg_font); + CGContextSetFontSize(gr.mrContext, CTFontGetSize(m_style->GetFont())); + CGContextSetTextDrawingMode(gr.mrContext, kCGTextFill); + CGContextSetShouldAntialias( gr.mrContext, true ); + if (m_style->GetColor()) + { + CGContextSetFillColorWithColor(gr.mrContext, m_style->GetColor()); + CGContextSetStrokeColorWithColor(gr.mrContext, m_style->GetColor()); + } + else + { + CGContextSetRGBFillColor(gr.mrContext, 0.0, 0.0, 0.0, 1.0); + } + CFRelease(cg_font); +// CGContextSetTextPosition(gr.mrContext, pos.X(), pos.Y()); + CGContextSetTextMatrix(gr.mrContext, CGAffineTransformMakeScale(1.0, -1.0)); + CGContextSetShouldAntialias( gr.mrContext, !gr.mbNonAntialiasedText ); + CGContextTranslateCTM(gr.mrContext, pos.X(), pos.Y()); +// for(int i = 0; i < m_glyphs_count ; ++i) +// { +// msgs_debug(layout,"m_glyph=%p m_glyph_positions=%p count=%d", m_glyphs, m_glyph_positions, m_glyphs_count); +// msgs_debug(layout,"glyph[%d]=0x%x position(%g,%g)", i, m_glyphs[i], m_glyph_positions[i].x, m_glyph_positions[i].y); + CGContextShowGlyphs(gr.mrContext, m_glyphs, m_glyphs_count); +// CGContextShowGlyphsAtPositions(gr.mrContext, m_glyphs, m_glyph_positions, m_glyphs_count); +// CGContextShowGlyphsWidthAdvances(gr.mrContext, m_glyphs, m_glyph_advances, m_glyphs_count); + +// CGContextShowGlyphsAtPoint(gr.mrContext, pos.X(), pos.Y(), m_glyphs, m_glyphs_count); +// } +#endif + // restore the original graphic context transformations + CGContextRestoreGState( gr.mrContext ); + msgs_debug(layout,"<--"); - // Implement... - - return 0; } -long CoreTextLayout::GetTextWidth() const -{ - // Implement... - - return 0; -} +// not needed. CoreText manage fallback directly +void CoreTextLayout::DropGlyph( int /*nStart*/ ) {} long CoreTextLayout::FillDXArray( long* pDXArray ) const { + msgs_debug(layout,"-->"); // short circuit requests which don't need full details - if( !pDXArray ) + if ( !pDXArray ) + { return GetTextWidth(); - - // Implement... - - return 0; + } + // check assumptions + DBG_ASSERT( !mnTrailingSpaceWidth, "CoreText::FillDXArray() with nTSW!=0" ); + + // initialize details about the resulting layout + InitGIA(); + + // distribute the widths among the string elements + long width = 0; + float scale = m_style->GetFontStretchFactor(); + m_cached_width = 0; + + for( int i = 0; i < m_chars_count; ++i ) + { + // convert and adjust for accumulated rounding errors + m_cached_width += m_char_widths[i]; + const long old_width = width; + width = round_to_long(m_cached_width * scale); + pDXArray[i] = width - old_width; + } + msgs_debug(layout," w=%ld <--", width); + return width; } -int CoreTextLayout::GetTextBreak( long nMaxWidth, long nCharExtra, int nFactor ) const +bool CoreTextLayout::GetBoundRect( SalGraphics &rGraphics, Rectangle& rVCLRect ) const { - (void) nMaxWidth; - (void) nCharExtra; - (void) nFactor; - // Implement... - return 0; -} - -void CoreTextLayout::GetCaretPositions( int nMaxIndex, long* pCaretXArray ) const -{ - (void) nMaxIndex; - (void) pCaretXArray; - // Implement... -} - -bool CoreTextLayout::GetBoundRect( SalGraphics&, Rectangle& rVCLRect ) const -{ - (void) rVCLRect; - // Implement; + msgs_debug(layout,"-->"); + IosSalGraphics& gr = static_cast<IosSalGraphics&>(rGraphics); + if ( !m_has_bound_rec ) + { + CGRect bound_rect = CTLineGetImageBounds( m_line, gr.mrContext ); + if ( !CGRectIsNull( bound_rect ) ) + { + m_bound_rect = Rectangle( + Point( round_to_long(bound_rect.origin.x * m_style->GetFontStretchFactor()), + round_to_long(bound_rect.origin.y - bound_rect.size.height )), + Size( round_to_long(bound_rect.size.width * m_style->GetFontStretchFactor()), round_to_long(bound_rect.size.height))); + m_bound_rect.Justify(); + } + m_has_bound_rec = true; + } + rVCLRect = m_bound_rect; + msgs_debug(layout,"<--"); return true; } -bool CoreTextLayout::InitGIA( ImplLayoutArgs* pArgs ) const +void CoreTextLayout::GetCaretPositions( int max_index, long* caret_position) const { - (void) pArgs; - // no need to run InitGIA more than once on the same CoreTextLayout object - if( mnGlyphCount >= 0 ) - return true; - mnGlyphCount = 0; - - // Implement... - - return true; + msgs_debug(layout,"max_index %d -->", max_index); + int local_max = max_index < m_chars_count * 2 ? max_index : m_chars_count; + for(int i = 0 ; i < max_index - 1; i+=2) + { + CGFloat primary, secondary; + primary = CTLineGetOffsetForStringIndex(m_line, i >> 1, &secondary); + caret_position[i] = round_to_long(m_base_advance + primary); + caret_position[i+1] = round_to_long(m_base_advance + secondary); + i += 2; + } + for(int i = local_max ; i < max_index ; ++i) + { + caret_position[i] = -1; + } + msgs_debug(layout,"<--"); } -// ----------------------------------------------------------------------- +bool CoreTextLayout::GetGlyphOutlines( SalGraphics&, PolyPolyVector& ) const { return false; } -bool CoreTextLayout::GetIdealX() const +int CoreTextLayout::GetNextGlyphs( int nLen, sal_GlyphId* pGlyphIDs, Point& rPos, int& nStart, + sal_Int32* pGlyphAdvances, int* pCharIndexes ) const { - // compute the ideal advance widths only once - if( mpGlyphOrigAdvs != NULL ) - return true; - - // Implement... + msgs_debug(layout,"nLen=%d nStart=%d-->", nLen, nStart); + // get glyph measurements + InitGIA(); - return true; + if ( nStart < 0 ) // first glyph requested? + { + nStart = 0; + m_current_run_index = 0; + m_current_glyph_index = 0; + m_current_glyphrun_index = 0; + } + else if (nStart >= m_glyphs_count) + { + m_current_run_index = 0; + m_current_glyph_index = 0; + m_current_glyphrun_index = 0; + return 0; + } + if (!m_runs) + { + m_runs = CTLineGetGlyphRuns(m_line); + } + CFIndex nb_runs = CFArrayGetCount( m_runs ); + CTRunRef run = (CTRunRef)CFArrayGetValueAtIndex( m_runs, m_current_run_index ); + CFIndex nb_glyphs = CTRunGetGlyphCount( run ); + + int i = 0; + bool first = true; + while(i < nLen) + { + if (m_current_glyphrun_index >= nb_glyphs) + { + m_current_run_index += 1; + if (m_current_run_index >= nb_runs) + { + break; + } + run = (CTRunRef)CFArrayGetValueAtIndex( m_runs, m_current_run_index ); + nb_glyphs = CTRunGetGlyphCount( run ); + m_current_glyphrun_index = 0; + } + if (first) + { + CGPoint first_pos; + CTRunGetPositions(run, CFRangeMake(m_current_glyphrun_index,1), &first_pos); + Point pos(first_pos.x, first_pos.y); + rPos = GetDrawPosition(pos); + msgs_debug(layout,"rPos(%ld, %ld)", rPos.X(),rPos.Y()); + first = false; + } + pGlyphIDs[i] = m_glyphs[m_current_glyph_index]; + if (pGlyphAdvances) + { + pGlyphAdvances[i] = m_glyph_advances[m_current_glyph_index]; + } + if (pCharIndexes) + { + pCharIndexes[i] = m_glyphs2chars[m_current_glyph_index]; + } + m_current_glyph_index += 1; + m_current_glyphrun_index += 1; + i += 1; + nStart += 1; + } + msgs_debug(layout,"i=%d <--", i); + return i; } -// ----------------------------------------------------------------------- - -bool CoreTextLayout::GetDeltaY() const +int CoreTextLayout::GetTextBreak( long /*nMaxWidth*/, long /*nCharExtra*/, int /*nFactor*/ ) const { - return true; + /* TODO */ + return false; } -// ----------------------------------------------------------------------- - -#define DELETEAZ( X ) { delete[] X; X = NULL; } - -void CoreTextLayout::InvalidateMeasurements() +long CoreTextLayout::GetTextWidth() const { - mnGlyphCount = -1; - DELETEAZ( mpGlyphIds ); - DELETEAZ( mpCharWidths ); - DELETEAZ( mpChars2Glyphs ); - DELETEAZ( mpGlyphs2Chars ); - DELETEAZ( mpGlyphRTLFlags ); - DELETEAZ( mpGlyphAdvances ); - DELETEAZ( mpGlyphOrigAdvs ); - DELETEAZ( mpDeltaY ); -} + msgs_debug(layout,"-->"); -// glyph fallback is supported directly by Ios -// so methods used only by MultiSalLayout can be dummy implementated -bool CoreTextLayout::GetGlyphOutlines( SalGraphics&, PolyPolyVector& ) const { return false; } -void CoreTextLayout::InitFont() const {} -void CoreTextLayout::MoveGlyph( int /*nStart*/, long /*nNewXPos*/ ) {} -void CoreTextLayout::DropGlyph( int /*nStart*/ ) {} -void CoreTextLayout::Simplify( bool /*bIsBase*/ ) {} - -// get the ImplFontData for a glyph fallback font -// for a glyphid that was returned by CoreTextLayout::GetNextGlyphs() -const ImplFontData* CoreTextLayout::GetFallbackFontData( sal_GlyphId nGlyphId ) const -{ - // check if any fallback fonts were needed - if( !mpFallbackInfo ) - return NULL; - // check if the current glyph needs a fallback font - int nFallbackLevel = (nGlyphId & GF_FONTMASK) >> GF_FONTSHIFT; - if( !nFallbackLevel ) - return NULL; - return mpFallbackInfo->GetFallbackFontData( nFallbackLevel ); + CGRect bound_rect = CTLineGetImageBounds(m_line, m_graphics->GetContext()); + long w = round_to_long(bound_rect.size.width * m_style->GetFontStretchFactor()); + msgs_debug(layout,"w=%ld <--", w); + return w; } -int FallbackInfo::AddFallback( CTFontRef nFontId ) +// not needed. CoreText manage fallback directly +void CoreTextLayout::InitFont() const { - (void) nFontId; - // Implement... - return 0; } -const ImplFontData* FallbackInfo::GetFallbackFontData( int nFallbackLevel ) const +bool CoreTextLayout::InitGIA() const { - const ImplIosFontData* pFallbackFont = maFontData[ nFallbackLevel-1 ]; - return pFallbackFont; + msgs_debug(layout,"count=%d <--", m_chars_count); + + if ( m_chars_count <= 0) + { + return false; + } + if (m_glyphs) + { + return true; + } + + m_glyphs = new CGGlyph[m_glyphs_count]; + m_char_widths = new int[ m_chars_count ]; + m_chars2glyphs = new int[ m_chars_count ]; + for( int i = 0; i < m_chars_count; ++i) + { + m_char_widths[i] = 0.0; + m_chars2glyphs[i] = -1; + } + m_glyphs2chars = new int[m_glyphs_count]; + m_glyph_advances = new int[m_glyphs_count]; + m_glyph_positions = new CGPoint[m_glyphs_count]; + + + CFArrayRef runs = CTLineGetGlyphRuns( m_line ); + CFIndex nb_runs = CFArrayGetCount( runs ); + int p = 0; + for( CFIndex i = 0; i < nb_runs; ++i ) + { + CTRunRef run = (CTRunRef)CFArrayGetValueAtIndex( runs, i ); + if ( run ) + { + CFIndex nb_glyphs = CTRunGetGlyphCount( run ); + if (nb_glyphs) + { + CFRange text_range = CTRunGetStringRange( run ); + if ( text_range.location != kCFNotFound && text_range.length > 0 ) + { + CFIndex indices[ nb_glyphs ]; + CGGlyph glyphs[ nb_glyphs ]; + CTRunGetStringIndices( run, CFRangeMake( 0, 0 ), indices ); + CTRunGetGlyphs( run, CFRangeMake( 0, 0 ), glyphs ); + CTRunGetPositions( run, CFRangeMake( 0, 0 ), &m_glyph_positions[p] ); + bool is_vertical_run = false; + CFDictionaryRef aDict = CTRunGetAttributes( run ); + if ( aDict ) + { + const CFBooleanRef aValue = (const CFBooleanRef)CFDictionaryGetValue( aDict, kCTVerticalFormsAttributeName ); + is_vertical_run = (aValue == kCFBooleanTrue) ? true : false; + } + + for (CFIndex j = 0 ; j < nb_glyphs; ++p, ++j ) + { + m_glyphs[ p ] = glyphs[ j ]; + CFIndex k = indices[ j ]; + m_glyphs2chars[p] = k; + m_chars2glyphs[k] = p; + + if ( j < nb_glyphs - 1 ) + { + m_char_widths[ k ] += m_glyph_positions[ p + 1 ].x - m_glyph_positions[ p ].x; + } + if ( p > 0) + { + m_glyph_advances[p - 1] = m_glyph_positions[ p ].x - m_glyph_positions[p - 1].x; + } + } + } + } + } + } + msgs_debug(layout,"<--"); + return true; } -SalLayout* IosSalGraphics::GetTextLayout( ImplLayoutArgs&, int /*nFallbackLevel*/ ) +bool CoreTextLayout::LayoutText(ImplLayoutArgs& args) { - return 0; + msgs_debug(layout,"-->"); + Clean(); + m_style->SetColor(); + /* retreive MinCharPos EndCharPos Flags and Orientation */ + SalLayout::AdjustLayout(args); + m_chars_count = mnEndCharPos - mnMinCharPos; + + /* don't layout emptty (or worse negative size) strings */ + if (m_chars_count <= 0) + { + return false; + } + /* c0 and c1 are construction objects */ + CFStringRef c0 = CFStringCreateWithCharactersNoCopy( NULL, &(args.mpStr[args.mnMinCharPos]), m_chars_count, kCFAllocatorNull ); + if ( !c0 ) + { + Clean(); + return false; + } + + CFStringRef keys[6]; + CFTypeRef values[6]; + int nb_attributes = 0; + + keys[nb_attributes]= kCTFontAttributeName; + values[nb_attributes] = m_style->GetFont(); + nb_attributes += 1; + + CFDictionaryRef attributes = CFDictionaryCreate(kCFAllocatorDefault, + (const void**)&keys, + (const void**)&values, + nb_attributes, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + + + CFAttributedStringRef string = CFAttributedStringCreate( NULL, c0, attributes ); + CFRelease( c0 ); + CFRelease( attributes ); + if ( !string ) + { + Clean(); + return false; + } + m_typesetter = CTTypesetterCreateWithAttributedString(string); + CFRelease(string); + if (!m_typesetter) + { + Clean(); + return false; + } + m_line = CTTypesetterCreateLine(m_typesetter, CFRangeMake(0, 0)); + if (!m_line) + { + Clean(); + return false; + } + m_glyphs_count = CTLineGetGlyphCount(m_line); + + msgs_debug(layout,"glyph_count=%d <--", m_glyphs_count); + return true; } +// not needed. CoreText manage fallback directly +void CoreTextLayout::MoveGlyph( int /*nStart*/, long /*nNewXPos*/ ) {} + +// not needed. CoreText manage fallback directly +void CoreTextLayout::Simplify( bool /*bIsBase*/ ) {} + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/ios/source/gdi/salcoretextstyle.cxx b/vcl/ios/source/gdi/salcoretextstyle.cxx new file mode 100644 index 000000000000..00820783ad41 --- /dev/null +++ b/vcl/ios/source/gdi/salcoretextstyle.cxx @@ -0,0 +1,96 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + +#include "ios/common.h" +#include "outfont.hxx" +#include "ios/salcoretextfontutils.hxx" +#include "ios/salcoretextstyle.hxx" + +CoreTextStyleInfo::CoreTextStyleInfo() : + m_fake_bold(false), + m_fake_italic(false), + m_matrix(CGAffineTransformIdentity), + m_stretch_factor(1.0), + m_CTParagraphStyle(NULL), + m_CTFont(NULL), + m_color(NULL), + m_font_data(NULL) +{ + msgs_debug(style,"create <-->"); +} + +CoreTextStyleInfo::~CoreTextStyleInfo() +{ + msgs_debug(style,"destroy (font:%p) <-->", m_CTFont); + SafeCFRelease(m_CTFont); + SafeCFRelease(m_CTParagraphStyle); + SafeCFRelease(m_color); +} + +long CoreTextStyleInfo::GetFontStretchedSize() const +{ + CGFloat size = CTFontGetSize(m_CTFont); + return static_cast<long>(size * m_stretch_factor + 0.5); +} + +void CoreTextStyleInfo::SetFont(FontSelectPattern* requested_font) +{ + msgs_debug(style,"req(%p) release font %p -->", requested_font, m_CTFont); + SafeCFRelease(m_CTFont); + if (!requested_font) + { + m_font_data = NULL; + return; + } + const ImplCoreTextFontData* font_data = static_cast<const ImplCoreTextFontData*>(requested_font->mpFontData); + + m_font_data = (ImplCoreTextFontData*)font_data; + m_matrix = CGAffineTransformIdentity; + CGFloat font_size = (CGFloat)requested_font->mfExactHeight; + + // enable bold-emulation if needed + if ( (requested_font->GetWeight() >= WEIGHT_BOLD) && + (font_data->GetWeight() < WEIGHT_SEMIBOLD) ) + { + /* FIXME: add support for fake bold */ + m_fake_bold = true; + } + if ( ((requested_font->GetSlant() == ITALIC_NORMAL) || (requested_font->GetSlant() == ITALIC_OBLIQUE)) && + !((font_data->GetSlant() == ITALIC_NORMAL) || (font_data->GetSlant() == ITALIC_OBLIQUE)) ) + { +#define kRotationForItalicText 10 + m_fake_italic = true; + /* about 6 degree of slant */ + m_matrix = CGAffineTransformMake( 1, 0, -tanf( kRotationForItalicText * acosf(0) / 90 ), 1, 0, 0); + } + + // prepare font stretching + if ( (requested_font->mnWidth != 0) && (requested_font->mnWidth != requested_font->mnHeight) ) + { + m_stretch_factor = (float)requested_font->mnWidth / requested_font->mnHeight; + m_matrix = CGAffineTransformScale(m_matrix, m_stretch_factor, 1.0F ); + } + + /* FIXME: pass attribute to take into accout 'VerticalStyle' */ + /* FIXME: how to deal with 'rendering options' i.e anti-aliasing, does it even matter in CoreText ? */ + m_CTFont = CTFontCreateCopyWithAttributes(font_data->GetCTFont(), font_size, &m_matrix, NULL); + msgs_debug(style,"font %p <--", m_CTFont); +} + +void CoreTextStyleInfo::SetColor(SalColor color) +{ + msgs_debug(style, "r:%d g:%d b:%d -->", SALCOLOR_RED(color), SALCOLOR_GREEN(color), SALCOLOR_BLUE(color)); + SafeCFRelease(m_color); + CGColorSpaceRef rgb_space = CGColorSpaceCreateDeviceRGB(); + CGFloat c[] = { SALCOLOR_RED(color) / 255.0, SALCOLOR_GREEN(color) / 255.0, SALCOLOR_BLUE(color) / 255.0, 1.0 }; + m_color = CGColorCreate(rgb_space, c); + CGColorSpaceRelease(rgb_space); + msgs_debug(style,"color=%p <--", m_color); +} + +void CoreTextStyleInfo::SetColor(void) +{ + msgs_debug(style, "null -->"); + SafeCFRelease(m_color); + msgs_debug(style,"color=%p <--", m_color); +} +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/ios/source/gdi/salgdi.cxx b/vcl/ios/source/gdi/salgdi.cxx index 9b7a02098f40..f7f6bcdbcf26 100644 --- a/vcl/ios/source/gdi/salgdi.cxx +++ b/vcl/ios/source/gdi/salgdi.cxx @@ -26,257 +26,13 @@ * ************************************************************************/ +#include "ios/common.h" -#include "osl/file.hxx" -#include "osl/process.h" - -#include "osl/mutex.hxx" - -#include "rtl/bootstrap.h" -#include "rtl/strbuf.hxx" - -#include "basegfx/range/b2drectangle.hxx" -#include "basegfx/polygon/b2dpolygon.hxx" -#include "basegfx/polygon/b2dpolygontools.hxx" -#include "basegfx/matrix/b2dhommatrix.hxx" -#include "basegfx/matrix/b2dhommatrixtools.hxx" - -#include "vcl/sysdata.hxx" -#include "vcl/svapp.hxx" - -#include "ios/salconst.h" -#include "ios/salgdi.h" -#include "ios/salbmp.h" #include "ios/salframe.h" -#include "ios/salcolorutils.hxx" -#include "ios/salcoretextfontutils.hxx" - -#include "fontsubset.hxx" -#include "impfont.hxx" -#include "region.h" -#include "sallayout.hxx" -#include "sft.hxx" - - -using namespace vcl; - -typedef std::vector<unsigned char> ByteVector; - - -// ======================================================================= - -ImplIosFontData::ImplIosFontData( const ImplDevFontAttributes& rDFA, CTFontRef pFontRef ) -: ImplFontData( rDFA, 0 ) -, mpFontRef( pFontRef ) -, mpCharMap( NULL ) -, mbOs2Read( false ) -, mbHasOs2Table( false ) -, mbCmapEncodingRead( false ) -, mbHasCJKSupport( false ) -, mbFontCapabilitiesRead( false ) -{ -} - -// ----------------------------------------------------------------------- - -ImplIosFontData::~ImplIosFontData() -{ - if( mpCharMap ) - mpCharMap->DeReference(); -} - -// ----------------------------------------------------------------------- - -sal_IntPtr ImplIosFontData::GetFontId() const -{ - return (sal_IntPtr)mpFontRef; -} - -// ----------------------------------------------------------------------- - -ImplFontData* ImplIosFontData::Clone() const -{ - ImplIosFontData* pClone = new ImplIosFontData(*this); - if( mpCharMap ) - mpCharMap->AddReference(); - return pClone; -} - -// ----------------------------------------------------------------------- - -ImplFontEntry* ImplIosFontData::CreateFontInstance(FontSelectPattern& rFSD) const -{ - return new ImplFontEntry(rFSD); -} - -// ----------------------------------------------------------------------- - -inline FourCharCode GetTag(const char aTagName[5]) -{ - return (aTagName[0]<<24)+(aTagName[1]<<16)+(aTagName[2]<<8)+(aTagName[3]); -} - -static unsigned GetUShort( const unsigned char* p ){return((p[0]<<8)+p[1]);} -static unsigned GetUInt( const unsigned char* p ) { return((p[0]<<24)+(p[1]<<16)+(p[2]<<8)+p[3]);} - -const ImplFontCharMap* ImplIosFontData::GetImplFontCharMap() const -{ - // return the cached charmap - if( mpCharMap ) - return mpCharMap; - - // set the default charmap - mpCharMap = ImplFontCharMap::GetDefaultMap(); - mpCharMap->AddReference(); - - // get the CMAP raw data - CFDataRef pData = CTFontCopyTable( mpFontRef, kCTFontTableCmap, kCTFontTableOptionNoOptions ); - if( pData == NULL ) - return mpCharMap; - - // parse the CMAP - CmapResult aCmapResult; - if( !ParseCMAP( CFDataGetBytePtr( pData ), CFDataGetLength( pData ), aCmapResult ) ) { - CFRelease( pData ); - return mpCharMap; - } - CFRelease( pData ); - - mpCharMap = new ImplFontCharMap( aCmapResult ); - mpCharMap->AddReference(); - return mpCharMap; -} - -bool ImplIosFontData::GetImplFontCapabilities(vcl::FontCapabilities &rFontCapabilities) const -{ - // read this only once per font - if( mbFontCapabilitiesRead ) - { - rFontCapabilities = maFontCapabilities; - return !rFontCapabilities.maUnicodeRange.empty() || !rFontCapabilities.maCodePageRange.empty(); - } - mbFontCapabilitiesRead = true; - - // prepare to get the GSUB table raw data - CFDataRef pData = CTFontCopyTable( mpFontRef, kCTFontTableGSUB, kCTFontTableOptionNoOptions ); - if( pData != NULL ) - { - vcl::getTTScripts(maFontCapabilities.maGSUBScriptTags, CFDataGetBytePtr( pData ), CFDataGetLength( pData ) ); - CFRelease( pData ); - } - pData = CTFontCopyTable( mpFontRef, kCTFontTableOS2, kCTFontTableOptionNoOptions ); - if( pData != NULL ) - { - vcl::getTTCoverage( - maFontCapabilities.maUnicodeRange, - maFontCapabilities.maCodePageRange, - CFDataGetBytePtr( pData ), CFDataGetLength( pData ) ); - CFRelease( pData ); - } - rFontCapabilities = maFontCapabilities; - return !rFontCapabilities.maUnicodeRange.empty() || !rFontCapabilities.maCodePageRange.empty(); -} -// ----------------------------------------------------------------------- - -void ImplIosFontData::ReadOs2Table( void ) const -{ - // read this only once per font - if( mbOs2Read ) - return; - mbOs2Read = true; - - // get the OS/2 raw data - CFDataRef pData = CTFontCopyTable( mpFontRef, kCTFontTableOS2, kCTFontTableOptionNoOptions ); - if( pData == NULL ) - return; - - mbHasOs2Table = true; - - // parse the OS/2 raw data - // TODO: also analyze panose info, etc. - - // check if the fonts needs the "CJK extra leading" heuristic - const sal_uInt32 nVersion = GetUShort( CFDataGetBytePtr( pData ) ); - if( nVersion >= 0x0001 ) - { - sal_uInt32 ulUnicodeRange2 = GetUInt( CFDataGetBytePtr( pData ) + 46 ); - if( ulUnicodeRange2 & 0x2DF00000 ) - mbHasCJKSupport = true; - } - CFRelease( pData ); -} - -void ImplIosFontData::ReadIosCmapEncoding( void ) const -{ - // From the ATS framework, not present in the iOS SDK. Define only - // the enum values actually used here to avoid copy-pasteing too - // much... - - enum { - kFontMacintoshPlatform = 1, - }; - - enum { - kFontJapaneseScript = 1, - kFontTraditionalChineseScript = 2, - kFontChineseScript = kFontTraditionalChineseScript, - kFontKoreanScript = 3, - kFontSimpleChineseScript = 25, - }; - - // read this only once per font - if( mbCmapEncodingRead ) - return; - mbCmapEncodingRead = true; - - CFDataRef pData = CTFontCopyTable( mpFontRef, kCTFontTableCmap, kCTFontTableOptionNoOptions ); - DBG_ASSERT( (pData!=NULL), "ImplIosFontData::ReadIosCmapEncoding : CTFontCopyTable failed!\n"); - if( pData == NULL ) - return; - - if ( CFDataGetLength( pData ) < 24 ) { - CFRelease( pData ); - return; - } - if( GetUShort( CFDataGetBytePtr( pData ) ) != 0x0000 ) { - CFRelease( pData ); - return; - } - - // check if the fonts needs the "CJK extra leading" heuristic - int nSubTables = GetUShort( CFDataGetBytePtr( pData ) + 2 ); - - for( const unsigned char* p = CFDataGetBytePtr( pData ) + 4; --nSubTables >= 0; p += 8 ) - { - int nPlatform = GetUShort( p ); - if( nPlatform == kFontMacintoshPlatform ) { - int nEncoding = GetUShort (p + 2 ); - if( nEncoding == kFontJapaneseScript || - nEncoding == kFontTraditionalChineseScript || - nEncoding == kFontKoreanScript || - nEncoding == kFontSimpleChineseScript ) - { - mbHasCJKSupport = true; - break; - } - } - } - CFRelease( pData ); -} - -// ----------------------------------------------------------------------- - -bool ImplIosFontData::HasCJKSupport( void ) const -{ - ReadOs2Table(); - if( !mbHasOs2Table ) - ReadIosCmapEncoding(); - - return mbHasCJKSupport; -} - -// ======================================================================= +#include "ios/salgdi.h" +#include "ios/salcoretextstyle.hxx" +#include "ios/salcoretextlayout.hxx" IosSalGraphics::IosSalGraphics() : mpFrame( NULL ) @@ -293,2136 +49,212 @@ IosSalGraphics::IosSalGraphics() , mxClipPath( NULL ) , maLineColor( COL_WHITE ) , maFillColor( COL_BLACK ) - , mpIosFontData( NULL ) - , mnRotation( 0 ) - , mfFontStretch( 1.0 ) + , m_pCoreTextFontData( NULL ) , mbNonAntialiasedText( false ) , mbPrinter( false ) , mbVirDev( false ) , mbWindow( false ) { - // create the style object for font attributes - mpAttributes = [NSMutableDictionary dictionary]; + msgs_debug(gr,"-->"); + m_style = new CoreTextStyleInfo(); + msgs_debug(gr,"m_style=%p <--", m_style); } -// ----------------------------------------------------------------------- - IosSalGraphics::~IosSalGraphics() { -/* - if( mnUpdateGraphicsEvent ) - { - Application::RemoveUserEvent( mnUpdateGraphicsEvent ); - } -*/ - CGPathRelease( mxClipPath ); - [mpAttributes release]; - - if( mpXorEmulation ) - delete mpXorEmulation; - - if( mxLayer ) - CGLayerRelease( mxLayer ); - else if( mrContext && mbWindow ) - { - // destroy backbuffer bitmap context that we created ourself - CGContextRelease( mrContext ); - mrContext = NULL; - // memory is freed automatically by maOwnContextMemory - } -} - -bool IosSalGraphics::supportsOperation( OutDevSupportType eType ) const -{ - bool bRet = false; - switch( eType ) - { - case OutDevSupport_TransparentRect: - case OutDevSupport_B2DClip: - case OutDevSupport_B2DDraw: - bRet = true; - break; - default: break; - } - return bRet; -} - -// ======================================================================= - -void IosSalGraphics::updateResolution() -{ - DBG_ASSERT( mbWindow, "updateResolution on inappropriate graphics" ); - - initResolution( (mbWindow && mpFrame) ? mpFrame->mpWindow : nil ); -} - -void IosSalGraphics::initResolution( UIWindow* ) -{ - // #i100617# read DPI only once; there is some kind of weird caching going on - // if the main screen changes - // FIXME: this is really unfortunate and needs to be investigated - - SalData* pSalData = GetSalData(); - if( pSalData->mnDPIX == 0 || pSalData->mnDPIY == 0 ) - { - UIScreen* pScreen = [UIScreen mainScreen]; - - mnRealDPIX = mnRealDPIY = 160; - if( pScreen ) - { - mnRealDPIX *= [pScreen scale]; - mnRealDPIY *= [pScreen scale]; - } - else - { - OSL_FAIL( "no screen found" ); - } - - pSalData->mnDPIX = mnRealDPIX; - pSalData->mnDPIY = mnRealDPIY; - } - else - { - mnRealDPIX = pSalData->mnDPIX; - mnRealDPIY = pSalData->mnDPIY; - } - - mfFakeDPIScale = 1.0; -} - -void IosSalGraphics::GetResolution( long& rDPIX, long& rDPIY ) -{ - if( !mnRealDPIY ) - initResolution( (mbWindow && mpFrame) ? mpFrame->mpWindow : nil ); - - rDPIX = static_cast<long>(mfFakeDPIScale * mnRealDPIX); - rDPIY = static_cast<long>(mfFakeDPIScale * mnRealDPIY); -} - -void IosSalGraphics::copyResolution( IosSalGraphics& rGraphics ) -{ - if( !rGraphics.mnRealDPIY && rGraphics.mbWindow && rGraphics.mpFrame ) - rGraphics.initResolution( rGraphics.mpFrame->mpWindow ); - - mnRealDPIX = rGraphics.mnRealDPIX; - mnRealDPIY = rGraphics.mnRealDPIY; - mfFakeDPIScale = rGraphics.mfFakeDPIScale; -} - -// ----------------------------------------------------------------------- - -sal_uInt16 IosSalGraphics::GetBitCount() const -{ - sal_uInt16 nBits = mnBitmapDepth ? mnBitmapDepth : 32;//24; - return nBits; -} - -// ----------------------------------------------------------------------- - -static const basegfx::B2DPoint aHalfPointOfs ( 0.5, 0.5 ); - -static void AddPolygonToPath( CGMutablePathRef xPath, - const ::basegfx::B2DPolygon& rPolygon, bool bClosePath, bool bPixelSnap, bool bLineDraw ) -{ - // short circuit if there is nothing to do - const int nPointCount = rPolygon.count(); - if( nPointCount <= 0 ) - return; - - (void)bPixelSnap; // TODO - const CGAffineTransform* pTransform = NULL; - - const bool bHasCurves = rPolygon.areControlPointsUsed(); - for( int nPointIdx = 0, nPrevIdx = 0;; nPrevIdx = nPointIdx++ ) - { - int nClosedIdx = nPointIdx; - if( nPointIdx >= nPointCount ) - { - // prepare to close last curve segment if needed - if( bClosePath && (nPointIdx == nPointCount) ) - nClosedIdx = 0; - else - break; - } - - ::basegfx::B2DPoint aPoint = rPolygon.getB2DPoint( nClosedIdx ); - - if( bPixelSnap) - { - // snap device coordinates to full pixels - aPoint.setX( basegfx::fround( aPoint.getX() ) ); - aPoint.setY( basegfx::fround( aPoint.getY() ) ); - } - - if( bLineDraw ) - aPoint += aHalfPointOfs; - - if( !nPointIdx ) { // first point => just move there - CGPathMoveToPoint( xPath, pTransform, aPoint.getX(), aPoint.getY() ); - continue; - } - - bool bPendingCurve = false; - if( bHasCurves ) - { - bPendingCurve = rPolygon.isNextControlPointUsed( nPrevIdx ); - bPendingCurve |= rPolygon.isPrevControlPointUsed( nClosedIdx ); - } - - if( !bPendingCurve ) // line segment - CGPathAddLineToPoint( xPath, pTransform, aPoint.getX(), aPoint.getY() ); - else // cubic bezier segment - { - basegfx::B2DPoint aCP1 = rPolygon.getNextControlPoint( nPrevIdx ); - basegfx::B2DPoint aCP2 = rPolygon.getPrevControlPoint( nClosedIdx ); - if( bLineDraw ) - { - aCP1 += aHalfPointOfs; - aCP2 += aHalfPointOfs; - } - CGPathAddCurveToPoint( xPath, pTransform, aCP1.getX(), aCP1.getY(), - aCP2.getX(), aCP2.getY(), aPoint.getX(), aPoint.getY() ); - } - } - - if( bClosePath ) - CGPathCloseSubpath( xPath ); -} - -static void AddPolyPolygonToPath( CGMutablePathRef xPath, - const ::basegfx::B2DPolyPolygon& rPolyPoly, bool bPixelSnap, bool bLineDraw ) -{ - // short circuit if there is nothing to do - const int nPolyCount = rPolyPoly.count(); - if( nPolyCount <= 0 ) - return; - - for( int nPolyIdx = 0; nPolyIdx < nPolyCount; ++nPolyIdx ) - { - const ::basegfx::B2DPolygon rPolygon = rPolyPoly.getB2DPolygon( nPolyIdx ); - AddPolygonToPath( xPath, rPolygon, true, bPixelSnap, bLineDraw ); - } -} - -// ----------------------------------------------------------------------- - -void IosSalGraphics::ResetClipRegion() -{ - // release old path and indicate no clipping - if( mxClipPath ) - { - CGPathRelease( mxClipPath ); - mxClipPath = NULL; - } - if( CheckContext() ) - SetState(); -} - -// ----------------------------------------------------------------------- - -bool IosSalGraphics::setClipRegion( const Region& i_rClip ) -{ - // release old clip path - if( mxClipPath ) - { - CGPathRelease( mxClipPath ); - mxClipPath = NULL; - } - mxClipPath = CGPathCreateMutable(); - - // set current path, either as polypolgon or sequence of rectangles - if( i_rClip.HasPolyPolygon() ) - { - basegfx::B2DPolyPolygon aClip( const_cast<Region&>(i_rClip).ConvertToB2DPolyPolygon() ); - AddPolyPolygonToPath( mxClipPath, aClip, !getAntiAliasB2DDraw(), false ); - } - else - { - long nX, nY, nW, nH; - ImplRegionInfo aInfo; - bool bRegionRect = i_rClip.ImplGetFirstRect(aInfo, nX, nY, nW, nH ); - while( bRegionRect ) - { - if( nW && nH ) - { - CGRect aRect = {{nX,nY}, {nW,nH}}; - CGPathAddRect( mxClipPath, NULL, aRect ); - } - bRegionRect = i_rClip.ImplGetNextRect( aInfo, nX, nY, nW, nH ); - } - } - // set the current path as clip region - if( CheckContext() ) - SetState(); - return true; -} - -// ----------------------------------------------------------------------- - -void IosSalGraphics::SetLineColor() -{ - maLineColor.SetAlpha( 0.0 ); // transparent - if( CheckContext() ) - CGContextSetStrokeColor( mrContext, maLineColor.AsArray() ); -} - -// ----------------------------------------------------------------------- - -void IosSalGraphics::SetLineColor( SalColor nSalColor ) -{ - maLineColor = RGBAColor( nSalColor ); - if( CheckContext() ) - CGContextSetStrokeColor( mrContext, maLineColor.AsArray() ); -} - -// ----------------------------------------------------------------------- - -void IosSalGraphics::SetFillColor() -{ - maFillColor.SetAlpha( 0.0 ); // transparent - if( CheckContext() ) - CGContextSetFillColor( mrContext, maFillColor.AsArray() ); -} - -// ----------------------------------------------------------------------- - -void IosSalGraphics::SetFillColor( SalColor nSalColor ) -{ - maFillColor = RGBAColor( nSalColor ); - if( CheckContext() ) - CGContextSetFillColor( mrContext, maFillColor.AsArray() ); -} - -// ----------------------------------------------------------------------- - -static SalColor ImplGetROPSalColor( SalROPColor nROPColor ) -{ - SalColor nSalColor; - if ( nROPColor == SAL_ROP_0 ) - nSalColor = MAKE_SALCOLOR( 0, 0, 0 ); - else - nSalColor = MAKE_SALCOLOR( 255, 255, 255 ); - return nSalColor; -} - -void IosSalGraphics::SetROPLineColor( SalROPColor nROPColor ) -{ - if( ! mbPrinter ) - SetLineColor( ImplGetROPSalColor( nROPColor ) ); -} - -// ----------------------------------------------------------------------- - -void IosSalGraphics::SetROPFillColor( SalROPColor nROPColor ) -{ - if( ! mbPrinter ) - SetFillColor( ImplGetROPSalColor( nROPColor ) ); -} - -// ----------------------------------------------------------------------- - -void IosSalGraphics::ImplDrawPixel( long nX, long nY, const RGBAColor& rColor ) -{ - if( !CheckContext() ) - return; - - // overwrite the fill color - CGContextSetFillColor( mrContext, rColor.AsArray() ); - // draw 1x1 rect, there is no pixel drawing in Quartz - CGRect aDstRect = {{nX,nY,},{1,1}}; - CGContextFillRect( mrContext, aDstRect ); - RefreshRect( aDstRect ); - // reset the fill color - CGContextSetFillColor( mrContext, maFillColor.AsArray() ); -} - -void IosSalGraphics::drawPixel( long nX, long nY ) -{ - // draw pixel with current line color - ImplDrawPixel( nX, nY, maLineColor ); -} - -void IosSalGraphics::drawPixel( long nX, long nY, SalColor nSalColor ) -{ - const RGBAColor aPixelColor( nSalColor ); - ImplDrawPixel( nX, nY, aPixelColor ); -} - -// ----------------------------------------------------------------------- - -void IosSalGraphics::drawLine( long nX1, long nY1, long nX2, long nY2 ) -{ - if( nX1 == nX2 && nY1 == nY2 ) - { - // #i109453# platform independent code expects at least one pixel to be drawn - drawPixel( nX1, nY1 ); - return; - } - - if( !CheckContext() ) - return; - - CGContextBeginPath( mrContext ); - CGContextMoveToPoint( mrContext, static_cast<float>(nX1)+0.5, static_cast<float>(nY1)+0.5 ); - CGContextAddLineToPoint( mrContext, static_cast<float>(nX2)+0.5, static_cast<float>(nY2)+0.5 ); - CGContextDrawPath( mrContext, kCGPathStroke ); - - Rectangle aRefreshRect( nX1, nY1, nX2, nY2 ); -} - -// ----------------------------------------------------------------------- - -void IosSalGraphics::drawRect( long nX, long nY, long nWidth, long nHeight ) -{ - if( !CheckContext() ) - return; - - CGRect aRect( CGRectMake(nX, nY, nWidth, nHeight) ); - if( IsPenVisible() ) - { - aRect.origin.x += 0.5; - aRect.origin.y += 0.5; - aRect.size.width -= 1; - aRect.size.height -= 1; - } - - if( IsBrushVisible() ) - CGContextFillRect( mrContext, aRect ); - - if( IsPenVisible() ) - CGContextStrokeRect( mrContext, aRect ); - - RefreshRect( nX, nY, nWidth, nHeight ); -} - -// ----------------------------------------------------------------------- - -static void getBoundRect( sal_uLong nPoints, const SalPoint *pPtAry, long &rX, long& rY, long& rWidth, long& rHeight ) -{ - long nX1 = pPtAry->mnX; - long nX2 = nX1; - long nY1 = pPtAry->mnY; - long nY2 = nY1; - for( sal_uLong n = 1; n < nPoints; n++ ) - { - if( pPtAry[n].mnX < nX1 ) - nX1 = pPtAry[n].mnX; - else if( pPtAry[n].mnX > nX2 ) - nX2 = pPtAry[n].mnX; - - if( pPtAry[n].mnY < nY1 ) - nY1 = pPtAry[n].mnY; - else if( pPtAry[n].mnY > nY2 ) - nY2 = pPtAry[n].mnY; - } - rX = nX1; - rY = nY1; - rWidth = nX2 - nX1 + 1; - rHeight = nY2 - nY1 + 1; -} - -static inline void alignLinePoint( const SalPoint* i_pIn, float& o_fX, float& o_fY ) -{ - o_fX = static_cast<float>(i_pIn->mnX ) + 0.5; - o_fY = static_cast<float>(i_pIn->mnY ) + 0.5; -} - -void IosSalGraphics::drawPolyLine( sal_uLong nPoints, const SalPoint *pPtAry ) -{ - if( nPoints < 1 ) - return; - if( !CheckContext() ) - return; - - long nX = 0, nY = 0, nWidth = 0, nHeight = 0; - getBoundRect( nPoints, pPtAry, nX, nY, nWidth, nHeight ); - - float fX, fY; - - CGContextBeginPath( mrContext ); - alignLinePoint( pPtAry, fX, fY ); - CGContextMoveToPoint( mrContext, fX, fY ); - pPtAry++; - for( sal_uLong nPoint = 1; nPoint < nPoints; nPoint++, pPtAry++ ) - { - alignLinePoint( pPtAry, fX, fY ); - CGContextAddLineToPoint( mrContext, fX, fY ); - } - CGContextDrawPath( mrContext, kCGPathStroke ); - - RefreshRect( nX, nY, nWidth, nHeight ); -} - -// ----------------------------------------------------------------------- - -void IosSalGraphics::drawPolygon( sal_uLong nPoints, const SalPoint *pPtAry ) -{ - if( nPoints <= 1 ) - return; - if( !CheckContext() ) - return; - - long nX = 0, nY = 0, nWidth = 0, nHeight = 0; - getBoundRect( nPoints, pPtAry, nX, nY, nWidth, nHeight ); - - CGPathDrawingMode eMode; - if( IsBrushVisible() && IsPenVisible() ) - eMode = kCGPathEOFillStroke; - else if( IsPenVisible() ) - eMode = kCGPathStroke; - else if( IsBrushVisible() ) - eMode = kCGPathEOFill; - else - return; - - CGContextBeginPath( mrContext ); - - if( IsPenVisible() ) - { - float fX, fY; - alignLinePoint( pPtAry, fX, fY ); - CGContextMoveToPoint( mrContext, fX, fY ); - pPtAry++; - for( sal_uLong nPoint = 1; nPoint < nPoints; nPoint++, pPtAry++ ) - { - alignLinePoint( pPtAry, fX, fY ); - CGContextAddLineToPoint( mrContext, fX, fY ); - } - } - else - { - CGContextMoveToPoint( mrContext, pPtAry->mnX, pPtAry->mnY ); - pPtAry++; - for( sal_uLong nPoint = 1; nPoint < nPoints; nPoint++, pPtAry++ ) - CGContextAddLineToPoint( mrContext, pPtAry->mnX, pPtAry->mnY ); - } - - CGContextDrawPath( mrContext, eMode ); - RefreshRect( nX, nY, nWidth, nHeight ); -} - -// ----------------------------------------------------------------------- - -void IosSalGraphics::drawPolyPolygon( sal_uLong nPolyCount, const sal_uLong *pPoints, PCONSTSALPOINT *ppPtAry ) -{ - if( nPolyCount <= 0 ) - return; - if( !CheckContext() ) - return; - - // find bound rect - long leftX = 0, topY = 0, maxWidth = 0, maxHeight = 0; - getBoundRect( pPoints[0], ppPtAry[0], leftX, topY, maxWidth, maxHeight ); - for( sal_uLong n = 1; n < nPolyCount; n++ ) - { - long nX = leftX, nY = topY, nW = maxWidth, nH = maxHeight; - getBoundRect( pPoints[n], ppPtAry[n], nX, nY, nW, nH ); - if( nX < leftX ) - { - maxWidth += leftX - nX; - leftX = nX; - } - if( nY < topY ) - { - maxHeight += topY - nY; - topY = nY; - } - if( nX + nW > leftX + maxWidth ) - maxWidth = nX + nW - leftX; - if( nY + nH > topY + maxHeight ) - maxHeight = nY + nH - topY; - } - - // prepare drawing mode - CGPathDrawingMode eMode; - if( IsBrushVisible() && IsPenVisible() ) - eMode = kCGPathEOFillStroke; - else if( IsPenVisible() ) - eMode = kCGPathStroke; - else if( IsBrushVisible() ) - eMode = kCGPathEOFill; - else - return; - - // convert to CGPath - CGContextBeginPath( mrContext ); - if( IsPenVisible() ) - { - for( sal_uLong nPoly = 0; nPoly < nPolyCount; nPoly++ ) - { - const sal_uLong nPoints = pPoints[nPoly]; - if( nPoints > 1 ) - { - const SalPoint *pPtAry = ppPtAry[nPoly]; - float fX, fY; - alignLinePoint( pPtAry, fX, fY ); - CGContextMoveToPoint( mrContext, fX, fY ); - pPtAry++; - for( sal_uLong nPoint = 1; nPoint < nPoints; nPoint++, pPtAry++ ) - { - alignLinePoint( pPtAry, fX, fY ); - CGContextAddLineToPoint( mrContext, fX, fY ); - } - CGContextClosePath(mrContext); - } - } - } - else - { - for( sal_uLong nPoly = 0; nPoly < nPolyCount; nPoly++ ) - { - const sal_uLong nPoints = pPoints[nPoly]; - if( nPoints > 1 ) - { - const SalPoint *pPtAry = ppPtAry[nPoly]; - CGContextMoveToPoint( mrContext, pPtAry->mnX, pPtAry->mnY ); - pPtAry++; - for( sal_uLong nPoint = 1; nPoint < nPoints; nPoint++, pPtAry++ ) - CGContextAddLineToPoint( mrContext, pPtAry->mnX, pPtAry->mnY ); - CGContextClosePath(mrContext); - } - } - } - - CGContextDrawPath( mrContext, eMode ); - - RefreshRect( leftX, topY, maxWidth, maxHeight ); -} - -// ----------------------------------------------------------------------- - -bool IosSalGraphics::drawPolyPolygon( const ::basegfx::B2DPolyPolygon& rPolyPoly, - double fTransparency ) -{ - // short circuit if there is nothing to do - const int nPolyCount = rPolyPoly.count(); - if( nPolyCount <= 0 ) - return true; - - // ignore invisible polygons - if( (fTransparency >= 1.0) || (fTransparency < 0) ) - return true; - - // setup poly-polygon path - CGMutablePathRef xPath = CGPathCreateMutable(); - for( int nPolyIdx = 0; nPolyIdx < nPolyCount; ++nPolyIdx ) - { - const ::basegfx::B2DPolygon rPolygon = rPolyPoly.getB2DPolygon( nPolyIdx ); - AddPolygonToPath( xPath, rPolygon, true, !getAntiAliasB2DDraw(), IsPenVisible() ); - } - - const CGRect aRefreshRect = CGPathGetBoundingBox( xPath ); -#ifndef NO_I97317_WORKAROUND - // #i97317# workaround for Quartz having problems with drawing small polygons - if( ! ((aRefreshRect.size.width <= 0.125) && (aRefreshRect.size.height <= 0.125)) ) -#endif - { - // use the path to prepare the graphics context - CGContextSaveGState( mrContext ); - CGContextBeginPath( mrContext ); - CGContextAddPath( mrContext, xPath ); - - // draw path with antialiased polygon - CGContextSetShouldAntialias( mrContext, true ); - CGContextSetAlpha( mrContext, 1.0 - fTransparency ); - CGContextDrawPath( mrContext, kCGPathEOFillStroke ); - CGContextRestoreGState( mrContext ); - - // mark modified rectangle as updated - RefreshRect( aRefreshRect ); - } - - CGPathRelease( xPath ); - - return true; -} - -// ----------------------------------------------------------------------- - -bool IosSalGraphics::drawPolyLine( const ::basegfx::B2DPolygon& rPolyLine, - double fTransparency, - const ::basegfx::B2DVector& rLineWidths, - basegfx::B2DLineJoin eLineJoin ) -{ - // short circuit if there is nothing to do - const int nPointCount = rPolyLine.count(); - if( nPointCount <= 0 ) - return true; - - // reject requests that cannot be handled yet - if( rLineWidths.getX() != rLineWidths.getY() ) - return false; - - // #i101491# Ios does not support B2DLINEJOIN_NONE; return false to use - // the fallback (own geometry preparation) - // #i104886# linejoin-mode and thus the above only applies to "fat" lines - if( (basegfx::B2DLINEJOIN_NONE == eLineJoin) - && (rLineWidths.getX() > 1.3) ) - return false; - - // setup line attributes - CGLineJoin aCGLineJoin = kCGLineJoinMiter; - switch( eLineJoin ) { - case ::basegfx::B2DLINEJOIN_NONE: aCGLineJoin = /*TODO?*/kCGLineJoinMiter; break; - case ::basegfx::B2DLINEJOIN_MIDDLE: aCGLineJoin = /*TODO?*/kCGLineJoinMiter; break; - case ::basegfx::B2DLINEJOIN_BEVEL: aCGLineJoin = kCGLineJoinBevel; break; - case ::basegfx::B2DLINEJOIN_MITER: aCGLineJoin = kCGLineJoinMiter; break; - case ::basegfx::B2DLINEJOIN_ROUND: aCGLineJoin = kCGLineJoinRound; break; - } - - // setup poly-polygon path - CGMutablePathRef xPath = CGPathCreateMutable(); - AddPolygonToPath( xPath, rPolyLine, rPolyLine.isClosed(), !getAntiAliasB2DDraw(), true ); - - const CGRect aRefreshRect = CGPathGetBoundingBox( xPath ); -#ifndef NO_I97317_WORKAROUND - // #i97317# workaround for Quartz having problems with drawing small polygons - if( ! ((aRefreshRect.size.width <= 0.125) && (aRefreshRect.size.height <= 0.125)) ) -#endif - { - // use the path to prepare the graphics context - CGContextSaveGState( mrContext ); - CGContextAddPath( mrContext, xPath ); - // draw path with antialiased line - CGContextSetShouldAntialias( mrContext, true ); - CGContextSetAlpha( mrContext, 1.0 - fTransparency ); - CGContextSetLineJoin( mrContext, aCGLineJoin ); - CGContextSetLineWidth( mrContext, rLineWidths.getX() ); - CGContextDrawPath( mrContext, kCGPathStroke ); - CGContextRestoreGState( mrContext ); - - // mark modified rectangle as updated - RefreshRect( aRefreshRect ); - } - - CGPathRelease( xPath ); - - return true; -} - -// ----------------------------------------------------------------------- - -sal_Bool IosSalGraphics::drawPolyLineBezier( sal_uLong, const SalPoint*, const sal_uInt8* ) -{ - return sal_False; -} - -// ----------------------------------------------------------------------- - -sal_Bool IosSalGraphics::drawPolygonBezier( sal_uLong, const SalPoint*, const sal_uInt8* ) -{ - return sal_False; -} - -// ----------------------------------------------------------------------- - -sal_Bool IosSalGraphics::drawPolyPolygonBezier( sal_uLong, const sal_uLong*, - const SalPoint* const*, const sal_uInt8* const* ) -{ - return sal_False; -} - -// ----------------------------------------------------------------------- - -void IosSalGraphics::copyBits( const SalTwoRect *pPosAry, SalGraphics *pSrcGraphics ) -{ - if( !pSrcGraphics ) - pSrcGraphics = this; - - //from unix salgdi2.cxx - //[FIXME] find a better way to prevent calc from crashing when width and height are negative - if( pPosAry->mnSrcWidth <= 0 - || pPosAry->mnSrcHeight <= 0 - || pPosAry->mnDestWidth <= 0 - || pPosAry->mnDestHeight <= 0 ) - { - return; - } - - // accelerate trivial operations - /*const*/ IosSalGraphics* pSrc = static_cast<IosSalGraphics*>(pSrcGraphics); - const bool bSameGraphics = (this == pSrc) || (mbWindow && mpFrame && pSrc->mbWindow && (mpFrame == pSrc->mpFrame)); - if( bSameGraphics - && (pPosAry->mnSrcWidth == pPosAry->mnDestWidth) - && (pPosAry->mnSrcHeight == pPosAry->mnDestHeight)) - { - // short circuit if there is nothing to do - if( (pPosAry->mnSrcX == pPosAry->mnDestX) - && (pPosAry->mnSrcY == pPosAry->mnDestY)) - return; - // use copyArea() if source and destination context are identical - copyArea( pPosAry->mnDestX, pPosAry->mnDestY, pPosAry->mnSrcX, pPosAry->mnSrcY, - pPosAry->mnSrcWidth, pPosAry->mnSrcHeight, 0 ); - return; - } - - ApplyXorContext(); - pSrc->ApplyXorContext(); - - DBG_ASSERT( pSrc->mxLayer!=NULL, "IosSalGraphics::copyBits() from non-layered graphics" ); - - const CGPoint aDstPoint = { +pPosAry->mnDestX - pPosAry->mnSrcX, pPosAry->mnDestY - pPosAry->mnSrcY }; - if( (pPosAry->mnSrcWidth == pPosAry->mnDestWidth && pPosAry->mnSrcHeight == pPosAry->mnDestHeight) && - (!mnBitmapDepth || (aDstPoint.x + pSrc->mnWidth) <= mnWidth) ) // workaround a Quartz crasher - { - // in XOR mode the drawing context is redirected to the XOR mask - // if source and target are identical then copyBits() paints onto the target context though - CGContextRef xCopyContext = mrContext; - if( mpXorEmulation && mpXorEmulation->IsEnabled() ) - if( pSrcGraphics == this ) - xCopyContext = mpXorEmulation->GetTargetContext(); - - CGContextSaveGState( xCopyContext ); - const CGRect aDstRect = { {pPosAry->mnDestX, pPosAry->mnDestY}, {pPosAry->mnDestWidth, pPosAry->mnDestHeight} }; - CGContextClipToRect( xCopyContext, aDstRect ); - - // draw at new destination - // NOTE: flipped drawing gets disabled for this, else the subimage would be drawn upside down - if( pSrc->IsFlipped() ) - { CGContextTranslateCTM( xCopyContext, 0, +mnHeight ); CGContextScaleCTM( xCopyContext, +1, -1 ); } - // TODO: pSrc->size() != this->size() - ::CGContextDrawLayerAtPoint( xCopyContext, aDstPoint, pSrc->mxLayer ); - CGContextRestoreGState( xCopyContext ); - // mark the destination rectangle as updated - RefreshRect( aDstRect ); - } - else - { - SalBitmap* pBitmap = pSrc->getBitmap( pPosAry->mnSrcX, pPosAry->mnSrcY, pPosAry->mnSrcWidth, pPosAry->mnSrcHeight ); - - if( pBitmap ) - { - SalTwoRect aPosAry( *pPosAry ); - aPosAry.mnSrcX = 0; - aPosAry.mnSrcY = 0; - drawBitmap( &aPosAry, *pBitmap ); - delete pBitmap; - } - } -} - -// ----------------------------------------------------------------------- - -void IosSalGraphics::copyArea( long nDstX, long nDstY,long nSrcX, long nSrcY, long nSrcWidth, long nSrcHeight, sal_uInt16 /*nFlags*/ ) -{ - ApplyXorContext(); - - DBG_ASSERT( mxLayer!=NULL, "IosSalGraphics::copyArea() for non-layered graphics" ); - - // in XOR mode the drawing context is redirected to the XOR mask - // copyArea() always works on the target context though - CGContextRef xCopyContext = mrContext; - if( mpXorEmulation && mpXorEmulation->IsEnabled() ) - xCopyContext = mpXorEmulation->GetTargetContext(); - - // drawing a layer onto its own context causes trouble on OSX => copy it first - // TODO: is it possible to get rid of this unneeded copy more often? - // e.g. on OSX>=10.5 only this situation causes problems: - // mnBitmapDepth && (aDstPoint.x + pSrc->mnWidth) > mnWidth - CGLayerRef xSrcLayer = mxLayer; - // TODO: if( mnBitmapDepth > 0 ) - { - const CGSize aSrcSize = { nSrcWidth, nSrcHeight }; - xSrcLayer = ::CGLayerCreateWithContext( xCopyContext, aSrcSize, NULL ); - const CGContextRef xSrcContext = CGLayerGetContext( xSrcLayer ); - CGPoint aSrcPoint = { -nSrcX, -nSrcY }; - if( IsFlipped() ) - { - ::CGContextTranslateCTM( xSrcContext, 0, +nSrcHeight ); - ::CGContextScaleCTM( xSrcContext, +1, -1 ); - aSrcPoint.y = (nSrcY + nSrcHeight) - mnHeight; - } - ::CGContextDrawLayerAtPoint( xSrcContext, aSrcPoint, mxLayer ); - } - - // draw at new destination - const CGPoint aDstPoint = { +nDstX, +nDstY }; - ::CGContextDrawLayerAtPoint( xCopyContext, aDstPoint, xSrcLayer ); - - // cleanup - if( xSrcLayer != mxLayer ) - CGLayerRelease( xSrcLayer ); - - // mark the destination rectangle as updated - RefreshRect( nDstX, nDstY, nSrcWidth, nSrcHeight ); - -} - -// ----------------------------------------------------------------------- - -void IosSalGraphics::drawBitmap( const SalTwoRect* pPosAry, const SalBitmap& rSalBitmap ) -{ - if( !CheckContext() ) - return; - - const IosSalBitmap& rBitmap = static_cast<const IosSalBitmap&>(rSalBitmap); - CGImageRef xImage = rBitmap.CreateCroppedImage( (int)pPosAry->mnSrcX, (int)pPosAry->mnSrcY, (int)pPosAry->mnSrcWidth, (int)pPosAry->mnSrcHeight ); - if( !xImage ) - return; - - const CGRect aDstRect = {{pPosAry->mnDestX, pPosAry->mnDestY}, {pPosAry->mnDestWidth, pPosAry->mnDestHeight}}; - CGContextDrawImage( mrContext, aDstRect, xImage ); - CGImageRelease( xImage ); - RefreshRect( aDstRect ); -} - -// ----------------------------------------------------------------------- - -void IosSalGraphics::drawBitmap( const SalTwoRect* pPosAry, const SalBitmap& rSalBitmap,SalColor ) -{ - OSL_FAIL("not implemented for color masking!"); - drawBitmap( pPosAry, rSalBitmap ); -} - -// ----------------------------------------------------------------------- - -void IosSalGraphics::drawBitmap( const SalTwoRect* pPosAry, const SalBitmap& rSalBitmap, const SalBitmap& rTransparentBitmap ) -{ - if( !CheckContext() ) - return; - - const IosSalBitmap& rBitmap = static_cast<const IosSalBitmap&>(rSalBitmap); - const IosSalBitmap& rMask = static_cast<const IosSalBitmap&>(rTransparentBitmap); - CGImageRef xMaskedImage( rBitmap.CreateWithMask( rMask, pPosAry->mnSrcX, pPosAry->mnSrcY, pPosAry->mnSrcWidth, pPosAry->mnSrcHeight ) ); - if( !xMaskedImage ) - return; - - const CGRect aDstRect = {{pPosAry->mnDestX, pPosAry->mnDestY}, {pPosAry->mnDestWidth, pPosAry->mnDestHeight}}; - CGContextDrawImage( mrContext, aDstRect, xMaskedImage ); - CGImageRelease( xMaskedImage ); - RefreshRect( aDstRect ); -} - -// ----------------------------------------------------------------------- - -void IosSalGraphics::drawMask( const SalTwoRect* pPosAry, const SalBitmap& rSalBitmap, SalColor nMaskColor ) -{ - if( !CheckContext() ) - return; - - const IosSalBitmap& rBitmap = static_cast<const IosSalBitmap&>(rSalBitmap); - CGImageRef xImage = rBitmap.CreateColorMask( pPosAry->mnSrcX, pPosAry->mnSrcY, pPosAry->mnSrcWidth, pPosAry->mnSrcHeight, nMaskColor ); - if( !xImage ) - return; - - const CGRect aDstRect = {{pPosAry->mnDestX, pPosAry->mnDestY}, {pPosAry->mnDestWidth, pPosAry->mnDestHeight}}; - CGContextDrawImage( mrContext, aDstRect, xImage ); - CGImageRelease( xImage ); - RefreshRect( aDstRect ); -} - -// ----------------------------------------------------------------------- - -SalBitmap* IosSalGraphics::getBitmap( long nX, long nY, long nDX, long nDY ) -{ - DBG_ASSERT( mxLayer, "IosSalGraphics::getBitmap() with no layer" ); - - ApplyXorContext(); - - IosSalBitmap* pBitmap = new IosSalBitmap; - if( !pBitmap->Create( mxLayer, mnBitmapDepth, nX, nY, nDX, nDY, !mbWindow ) ) - { - delete pBitmap; - pBitmap = NULL; - } - - return pBitmap; -} - -// ----------------------------------------------------------------------- - -SalColor IosSalGraphics::getPixel( long nX, long nY ) -{ - // return default value on printers or when out of bounds - if( !mxLayer - || (nX < 0) || (nX >= mnWidth) - || (nY < 0) || (nY >= mnHeight)) - return COL_BLACK; - - // prepare creation of matching a CGBitmapContext - CGColorSpaceRef aCGColorSpace = GetSalData()->mxRGBSpace; - CGBitmapInfo aCGBmpInfo = kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Big; -#if __BIG_ENDIAN__ - struct{ unsigned char b, g, r, a; } aPixel; -#else - struct{ unsigned char a, r, g, b; } aPixel; -#endif - - // create a one-pixel bitmap context - // TODO: is it worth to cache it? - CGContextRef xOnePixelContext = ::CGBitmapContextCreate( &aPixel, - 1, 1, 8, sizeof(aPixel), aCGColorSpace, aCGBmpInfo ); - - // update this graphics layer - ApplyXorContext(); - - // copy the requested pixel into the bitmap context - if( IsFlipped() ) - nY = mnHeight - nY; - const CGPoint aCGPoint = {-nX, -nY}; - CGContextDrawLayerAtPoint( xOnePixelContext, aCGPoint, mxLayer ); - CGContextRelease( xOnePixelContext ); - - SalColor nSalColor = MAKE_SALCOLOR( aPixel.r, aPixel.g, aPixel.b ); - return nSalColor; -} - -// ----------------------------------------------------------------------- - - -static void DrawPattern50( void*, CGContextRef rContext ) -{ - static const CGRect aRects[2] = { { {0,0}, { 2, 2 } }, { { 2, 2 }, { 2, 2 } } }; - CGContextAddRects( rContext, aRects, 2 ); - CGContextFillPath( rContext ); -} - -void IosSalGraphics::Pattern50Fill() -{ - static const float aFillCol[4] = { 1,1,1,1 }; - static const CGPatternCallbacks aCallback = { 0, &DrawPattern50, NULL }; - if( ! GetSalData()->mxP50Space ) - GetSalData()->mxP50Space = CGColorSpaceCreatePattern( GetSalData()->mxRGBSpace ); - if( ! GetSalData()->mxP50Pattern ) - GetSalData()->mxP50Pattern = CGPatternCreate( NULL, CGRectMake( 0, 0, 4, 4 ), - CGAffineTransformIdentity, 4, 4, - kCGPatternTilingConstantSpacing, - false, &aCallback ); - - CGContextSetFillColorSpace( mrContext, GetSalData()->mxP50Space ); - CGContextSetFillPattern( mrContext, GetSalData()->mxP50Pattern, aFillCol ); - CGContextFillPath( mrContext ); -} - -void IosSalGraphics::invert( long nX, long nY, long nWidth, long nHeight, SalInvert nFlags ) -{ - if ( CheckContext() ) - { - CGRect aCGRect = CGRectMake( nX, nY, nWidth, nHeight); - CGContextSaveGState(mrContext); - - if ( nFlags & SAL_INVERT_TRACKFRAME ) - { - const float dashLengths[2] = { 4.0, 4.0 }; // for drawing dashed line - CGContextSetBlendMode( mrContext, kCGBlendModeDifference ); - CGContextSetRGBStrokeColor ( mrContext, 1.0, 1.0, 1.0, 1.0 ); - CGContextSetLineDash ( mrContext, 0, dashLengths, 2 ); - CGContextSetLineWidth( mrContext, 2.0); - CGContextStrokeRect ( mrContext, aCGRect ); - } - else if ( nFlags & SAL_INVERT_50 ) - { - //CGContextSetAllowsAntialiasing( mrContext, false ); - CGContextSetBlendMode(mrContext, kCGBlendModeDifference); - CGContextAddRect( mrContext, aCGRect ); - Pattern50Fill(); - } - else // just invert - { - CGContextSetBlendMode(mrContext, kCGBlendModeDifference); - CGContextSetRGBFillColor ( mrContext,1.0, 1.0, 1.0 , 1.0 ); - CGContextFillRect ( mrContext, aCGRect ); - } - CGContextRestoreGState( mrContext); - RefreshRect( aCGRect ); - } -} - -// ----------------------------------------------------------------------- - -void IosSalGraphics::invert( sal_uLong nPoints, const SalPoint* pPtAry, SalInvert nSalFlags ) -{ - CGPoint* CGpoints ; - if ( CheckContext() ) + msgs_debug(gr,"-->"); + if(m_style) { - CGContextSaveGState(mrContext); - CGpoints = makeCGptArray(nPoints,pPtAry); - CGContextAddLines ( mrContext, CGpoints, nPoints ); - if ( nSalFlags & SAL_INVERT_TRACKFRAME ) - { - const float dashLengths[2] = { 4.0, 4.0 }; // for drawing dashed line - CGContextSetBlendMode( mrContext, kCGBlendModeDifference ); - CGContextSetRGBStrokeColor ( mrContext, 1.0, 1.0, 1.0, 1.0 ); - CGContextSetLineDash ( mrContext, 0, dashLengths, 2 ); - CGContextSetLineWidth( mrContext, 2.0); - CGContextStrokePath ( mrContext ); - } - else if ( nSalFlags & SAL_INVERT_50 ) - { - CGContextSetBlendMode(mrContext, kCGBlendModeDifference); - Pattern50Fill(); - } - else // just invert - { - CGContextSetBlendMode( mrContext, kCGBlendModeDifference ); - CGContextSetRGBFillColor( mrContext, 1.0, 1.0, 1.0, 1.0 ); - CGContextFillPath( mrContext ); - } - const CGRect aRefreshRect = CGContextGetClipBoundingBox(mrContext); - CGContextRestoreGState( mrContext); - delete [] CGpoints; - RefreshRect( aRefreshRect ); + delete m_style; + m_style = NULL; } + msgs_debug(gr,"<--"); } -// ----------------------------------------------------------------------- - -sal_Bool IosSalGraphics::drawEPS( long /*nX*/, long /*nY*/, long /*nWidth*/, long /*nHeight*/, - void* /*pEpsData*/, sal_uLong /*nByteCount*/ ) +inline bool IosSalGraphics::AddTempDevFont( ImplDevFontList*, + const rtl::OUString& , + const rtl::OUString& ) { - return sal_False; + OSL_ASSERT( FALSE ); + return false; } -// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= -bool IosSalGraphics::drawAlphaBitmap( const SalTwoRect& rTR, - const SalBitmap& rSrcBitmap, const SalBitmap& rAlphaBmp ) -{ - // An image mask can't have a depth > 8 bits (should be 1 to 8 bits) - if( rAlphaBmp.GetBitCount() > 8 ) - return false; - - // are these two tests really necessary? (see vcl/unx/source/gdi/salgdi2.cxx) - // horizontal/vertical mirroring not implemented yet - if( rTR.mnDestWidth < 0 || rTR.mnDestHeight < 0 ) - return false; - - const IosSalBitmap& rSrcSalBmp = static_cast<const IosSalBitmap&>(rSrcBitmap); - const IosSalBitmap& rMaskSalBmp = static_cast<const IosSalBitmap&>(rAlphaBmp); - - CGImageRef xMaskedImage = rSrcSalBmp.CreateWithMask( rMaskSalBmp, rTR.mnSrcX, rTR.mnSrcY, rTR.mnSrcWidth, rTR.mnSrcHeight ); - if( !xMaskedImage ) - return false; - - if ( CheckContext() ) - { - const CGRect aDstRect = {{rTR.mnDestX, rTR.mnDestY}, {rTR.mnDestWidth, rTR.mnDestHeight}}; - CGContextDrawImage( mrContext, aDstRect, xMaskedImage ); - RefreshRect( aDstRect ); - } - - CGImageRelease(xMaskedImage); - return true; -} - -// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= -bool IosSalGraphics::drawAlphaRect( long nX, long nY, long nWidth, - long nHeight, sal_uInt8 nTransparency ) -{ - if( !CheckContext() ) - return true; - - // save the current state - CGContextSaveGState( mrContext ); - CGContextSetAlpha( mrContext, (100-nTransparency) * (1.0/100) ); - - CGRect aRect = {{nX,nY},{nWidth-1,nHeight-1}}; - if( IsPenVisible() ) - { - aRect.origin.x += 0.5; - aRect.origin.y += 0.5; - } - - CGContextBeginPath( mrContext ); - CGContextAddRect( mrContext, aRect ); - CGContextDrawPath( mrContext, kCGPathFill ); - - // restore state - CGContextRestoreGState(mrContext); - RefreshRect( aRect ); - return true; -} - -// ----------------------------------------------------------------------- - -void IosSalGraphics::SetTextColor( SalColor nSalColor ) -{ - mnColor = nSalColor; -} - -// ----------------------------------------------------------------------- - -void IosSalGraphics::GetFontMetric( ImplFontMetricData* pMetric, int nFallbackLevel ) -{ - (void)nFallbackLevel; - - const double fPixelSize = (mfFakeDPIScale * CTFontGetSize( mpIosFontData->mpFontRef )); - pMetric->mnAscent = CTFontGetAscent( mpIosFontData->mpFontRef ); - pMetric->mnDescent = -CTFontGetDescent( mpIosFontData->mpFontRef ); - pMetric->mnExtLeading = CTFontGetLeading( mpIosFontData->mpFontRef ); - pMetric->mnIntLeading = 0; - pMetric->mnWidth = static_cast<long>(mfFontStretch * fPixelSize + 0.5); -} - -// ----------------------------------------------------------------------- - -sal_uLong IosSalGraphics::GetKernPairs( sal_uLong, ImplKernPairData* ) +void IosSalGraphics::DrawServerFontLayout( const ServerFontLayout& ) { - return 0; } -// ----------------------------------------------------------------------- - -static bool AddLocalTempFontDirs( void ) +void IosSalGraphics::FreeEmbedFontData( const void* pData, long /*nDataLen*/ ) { - static bool bFirst = true; - if( !bFirst ) - return false; - bFirst = false; - - // add private font files - - rtl::OUString aBrandStr( RTL_CONSTASCII_USTRINGPARAM( "$BRAND_BASE_DIR" ) ); - rtl_bootstrap_expandMacros( &aBrandStr.pData ); - rtl::OUString aBrandSysPath; - OSL_VERIFY( osl_getSystemPathFromFileURL( aBrandStr.pData, &aBrandSysPath.pData ) == osl_File_E_None ); - - rtl::OStringBuffer aBrandFontDir( aBrandSysPath.getLength()*2 ); - aBrandFontDir.append( rtl::OUStringToOString( aBrandSysPath, RTL_TEXTENCODING_UTF8 ) ); - aBrandFontDir.append( "/share/fonts/truetype/" ); - - // iterate font files in that and call CTFontManagerRegisterFontsForURL for them? - bool bSuccess = true; - - return bSuccess; + // TODO: implementing this only makes sense when the implementation of + // IosSalGraphics::GetEmbedFontData() returns non-NULL + (void)pData; + DBG_ASSERT( (pData!=NULL), "IosSalGraphics::FreeEmbedFontData() is not implemented\n"); } void IosSalGraphics::GetDevFontList( ImplDevFontList* pFontList ) { DBG_ASSERT( pFontList, "IosSalGraphics::GetDevFontList(NULL) !"); - AddLocalTempFontDirs(); - - // The idea is to cache the list of system fonts once it has been generated. - // SalData seems to be a good place for this caching. However we have to - // carefully make the access to the font list thread-safe. If we register - // a font-change event handler to update the font list in case fonts have - // changed on the system we have to lock access to the list. The right - // way to do that is the solar mutex since GetDevFontList is protected - // through it as should be all event handlers - SalData* pSalData = GetSalData(); if (pSalData->mpFontList == NULL) + { pSalData->mpFontList = new SystemFontList(); - + } // Copy all ImplFontData objects contained in the SystemFontList pSalData->mpFontList->AnnounceFonts( *pFontList ); } -// ----------------------------------------------------------------------- - -bool IosSalGraphics::AddTempDevFont( ImplDevFontList*, - const rtl::OUString& rFontFileURL, const rtl::OUString& /*rFontName*/ ) -{ - ::rtl::OUString aUSytemPath; - OSL_VERIFY( !osl::FileBase::getSystemPathFromFileURL( rFontFileURL, aUSytemPath ) ); - - // TODO: Implement... - - return true; -} - -// ----------------------------------------------------------------------- - -// callbacks from ATSUGlyphGetCubicPaths() fore GetGlyphOutline() -struct GgoData { basegfx::B2DPolygon maPolygon; basegfx::B2DPolyPolygon* mpPolyPoly; }; - -sal_Bool IosSalGraphics::GetGlyphOutline( sal_GlyphId /*nGlyphId*/, basegfx::B2DPolyPolygon& rPolyPoly ) +void IosSalGraphics::GetDevFontSubstList( OutputDevice* ) { - GgoData aGgoData; - aGgoData.mpPolyPoly = &rPolyPoly; - rPolyPoly.clear(); - -#if 0 - ATSUStyle rATSUStyle = maATSUStyle; // TODO: handle glyph fallback when CWS pdffix02 is integrated - GlyphID aGlyphId = nGlyphId & GF_IDXMASK; - OSStatus eGgoStatus = noErr; - OSStatus eStatus = ATSUGlyphGetCubicPaths( rATSUStyle, aGlyphId, - GgoMoveToProc, GgoLineToProc, GgoCurveToProc, GgoClosePathProc, - &aGgoData, &eGgoStatus ); - if( (eStatus != noErr) ) // TODO: why is (eGgoStatus!=noErr) when curves are involved? - return false; - - GgoClosePathProc( &aGgoData ); -#endif - return true; + // nothing to do since there are no device-specific fonts on Ios } -// ----------------------------------------------------------------------- - -long IosSalGraphics::GetGraphicsWidth() const +const void* IosSalGraphics::GetEmbedFontData( const ImplFontData*, + const sal_Ucs* /*pUnicodes*/, + sal_Int32* /*pWidths*/, + FontSubsetInfo&, + long* /*pDataLen*/ ) { - long w = 0; - if( mrContext && (mbWindow || mbVirDev) ) - { - w = mnWidth; - } - - if( w == 0 ) - { - if( mbWindow && mpFrame ) - w = mpFrame->maGeometry.nWidth; - } - - return w; + return NULL; } -// ----------------------------------------------------------------------- - -sal_Bool IosSalGraphics::GetGlyphBoundRect( sal_GlyphId /*nGlyphId*/, Rectangle& rRect ) +const Ucs2SIntMap* IosSalGraphics::GetFontEncodingVector(const ImplFontData*, + const Ucs2OStrMap** /*ppNonEncoded*/ ) { -#if 0 - ATSUStyle rATSUStyle = maATSUStyle; // TODO: handle glyph fallback - GlyphID aGlyphId = nGlyphId & GF_IDXMASK; - ATSGlyphScreenMetrics aGlyphMetrics; - OSStatus eStatus = ATSUGlyphGetScreenMetrics( rATSUStyle, - 1, &aGlyphId, 0, FALSE, !mbNonAntialiasedText, &aGlyphMetrics ); - if( eStatus != noErr ) - return false; - - const long nMinX = (long)(+aGlyphMetrics.topLeft.x - 0.5); - const long nMaxX = (long)(aGlyphMetrics.width + 0.5) + nMinX; - const long nMinY = (long)(-aGlyphMetrics.topLeft.y - 0.5); - const long nMaxY = (long)(aGlyphMetrics.height + 0.5) + nMinY; - rRect = Rectangle( nMinX, nMinY, nMaxX, nMaxY ); -#else - rRect = Rectangle( ); -#endif - return true; + return NULL; } -// ----------------------------------------------------------------------- - -void IosSalGraphics::GetDevFontSubstList( OutputDevice* ) +void IosSalGraphics::GetFontMetric( ImplFontMetricData* pMetric, int nFallbackLevel ) { - // nothing to do since there are no device-specific fonts on Ios -} + (void)nFallbackLevel; // glyph-fallback on CoreText is done differently -> no fallback level -// ----------------------------------------------------------------------- + pMetric->mbScalableFont = true; + pMetric->mbKernableFont = true; + CTFontRef font = m_style->GetFont(); + DBG_ASSERT(font, "GetFontMetric without font set in style"); -void IosSalGraphics::DrawServerFontLayout( const ServerFontLayout& ) -{ + pMetric->mnAscent = static_cast<long>( CTFontGetAscent(font) * mfFakeDPIScale + 0.5); + pMetric->mnDescent = static_cast<long>(CTFontGetDescent(font) * mfFakeDPIScale + 0.5); + const long nExtDescent = static_cast<long>((CTFontGetLeading(font) + CTFontGetDescent(font)) * + mfFakeDPIScale + 0.5); + pMetric->mnExtLeading = nExtDescent + pMetric->mnDescent; + pMetric->mnIntLeading = 0; + pMetric->mnWidth = m_style->GetFontStretchedSize(); + msgs_debug(gr,"ascent=%ld, descent=%ld, extleading=%ld, intleading=%ld,w=%ld", + pMetric->mnAscent, pMetric->mnDescent, + pMetric->mnExtLeading, + pMetric->mnIntLeading, + pMetric->mnWidth); } -// ----------------------------------------------------------------------- - -sal_uInt16 IosSalGraphics::SetFont( FontSelectPattern* pReqFont, int /*nFallbackLevel*/ ) +sal_Bool IosSalGraphics::GetGlyphBoundRect( sal_GlyphId /*nGlyphId*/, Rectangle& /*rRect*/ ) { - if( !pReqFont ) - { - [mpAttributes removeAllObjects]; - mpIosFontData = NULL; - return 0; - } - - // store the requested device font entry - const ImplIosFontData* pIosFont = static_cast<const ImplIosFontData*>( pReqFont->mpFontData ); - mpIosFontData = pIosFont; - - // enable bold-emulation if needed - Boolean bFakeBold = FALSE; - if( (pReqFont->GetWeight() >= WEIGHT_BOLD) - && (pIosFont->GetWeight() < WEIGHT_SEMIBOLD) ) - bFakeBold = TRUE; - // enable italic-emulation if needed - Boolean bFakeItalic = FALSE; - if( ((pReqFont->GetSlant() == ITALIC_NORMAL) || (pReqFont->GetSlant() == ITALIC_OBLIQUE)) - && !((pIosFont->GetSlant() == ITALIC_NORMAL) || (pIosFont->GetSlant() == ITALIC_OBLIQUE)) ) - bFakeItalic = TRUE; - -#if 0 - // enable/disable antialiased text - mbNonAntialiasedText = pReqFont->mbNonAntialiased; - UInt32 nStyleRenderingOptions = kATSStyleNoOptions; - if( pReqFont->mbNonAntialiased ) - nStyleRenderingOptions |= kATSStyleNoAntiAliasing; - - // set horizontal/vertical mode - ATSUVerticalCharacterType aVerticalCharacterType = kATSUStronglyHorizontal; - if( pReqFont->mbVertical ) - aVerticalCharacterType = kATSUStronglyVertical; - - // prepare ATS-fontid as type matching to the kATSUFontTag request - ATSUFontID nFontID = static_cast<ATSUFontID>(pIosFont->GetFontId()); - - // update ATSU style attributes with requested font parameters - // TODO: no need to set styles which are already defaulted - - const ATSUAttributeTag aTag[] = - { - kATSUFontTag, - kATSUSizeTag, - kATSUQDBoldfaceTag, - kATSUQDItalicTag, - kATSUStyleRenderingOptionsTag, - kATSUVerticalCharacterTag - }; - - const ByteCount aValueSize[] = - { - sizeof(ATSUFontID), - sizeof(fFixedSize), - sizeof(bFakeBold), - sizeof(bFakeItalic), - sizeof(nStyleRenderingOptions), - sizeof(aVerticalCharacterType) - }; - - const ATSUAttributeValuePtr aValue[] = - { - &nFontID, - &fFixedSize, - &bFakeBold, - &bFakeItalic, - &nStyleRenderingOptions, - &aVerticalCharacterType - }; - - static const int nTagCount = SAL_N_ELEMENTS(aTag); - OSStatus eStatus = ATSUSetAttributes( maATSUStyle, nTagCount, - aTag, aValueSize, aValue ); - // reset ATSUstyle if there was an error - if( eStatus != noErr ) - { - DBG_WARNING( "IosSalGraphics::SetFont() : Could not set font attributes!\n"); - ATSUClearStyle( maATSUStyle ); - mpIosFontData = NULL; - return 0; - } - - // prepare font stretching - const ATSUAttributeTag aMatrixTag = kATSUFontMatrixTag; - if( (pReqFont->mnWidth == 0) || (pReqFont->mnWidth == pReqFont->mnHeight) ) - { - mfFontStretch = 1.0; - ATSUClearAttributes( maATSUStyle, 1, &aMatrixTag ); - } - else - { - mfFontStretch = (float)pReqFont->mnWidth / pReqFont->mnHeight; - CGAffineTransform aMatrix = CGAffineTransformMakeScale( mfFontStretch, 1.0F ); - const ATSUAttributeValuePtr aAttr = &aMatrix; - const ByteCount aMatrixBytes = sizeof(aMatrix); - eStatus = ATSUSetAttributes( maATSUStyle, 1, &aMatrixTag, &aMatrixBytes, &aAttr ); - DBG_ASSERT( (eStatus==noErr), "IosSalGraphics::SetFont() : Could not set font matrix\n"); - } - - // prepare font rotation - mnRotation = pReqFont->mnOrientation; - -#if OSL_DEBUG_LEVEL > 3 - fprintf( stderr, "SetFont to (\"%s\", \"%s\", fontid=%d) for (\"%s\" \"%s\" weight=%d, slant=%d size=%dx%d orientation=%d)\n", - ::rtl::OUStringToOString( pIosFont->GetFamilyName(), RTL_TEXTENCODING_UTF8 ).getStr(), - ::rtl::OUStringToOString( pIosFont->GetStyleName(), RTL_TEXTENCODING_UTF8 ).getStr(), - (int)nFontID, - ::rtl::OUStringToOString( pReqFont->GetFamilyName(), RTL_TEXTENCODING_UTF8 ).getStr(), - ::rtl::OUStringToOString( pReqFont->GetStyleName(), RTL_TEXTENCODING_UTF8 ).getStr(), - pReqFont->GetWeight(), - pReqFont->GetSlant(), - pReqFont->mnHeight, - pReqFont->mnWidth, - pReqFont->mnOrientation); -#endif - -#endif - return 0; + /* TODO: create a Ghyph iterator to keep track ot 'state' between call */ + return false; } -// ----------------------------------------------------------------------- - -const ImplFontCharMap* IosSalGraphics::GetImplFontCharMap() const +sal_Bool IosSalGraphics::GetGlyphOutline( sal_GlyphId /*nGlyphId*/, basegfx::B2DPolyPolygon& /*rPolyPoly*/ ) { - if( !mpIosFontData ) - return ImplFontCharMap::GetDefaultMap(); - - return mpIosFontData->GetImplFontCharMap(); + /* TODO */ + return false; } -bool IosSalGraphics::GetImplFontCapabilities(vcl::FontCapabilities &rFontCapabilities) const +void IosSalGraphics::GetGlyphWidths( const ImplFontData* /*pFontData*/, bool /*bVertical*/, + Int32Vector& /*rGlyphWidths*/, Ucs2UIntMap& /*rUnicodeEnc*/ ) { - if( !mpIosFontData ) - return false; - - return mpIosFontData->GetImplFontCapabilities(rFontCapabilities); } -// ----------------------------------------------------------------------- - -#if 0 - -// fake a SFNT font directory entry for a font table -// see http://developer.apple.com/textfonts/TTRefMan/RM06/Chap6.html#Directory -static void FakeDirEntry( FourCharCode eFCC, ByteCount nOfs, ByteCount nLen, - const unsigned char* /*pData*/, unsigned char*& rpDest ) +sal_uLong IosSalGraphics::GetKernPairs( sal_uLong, ImplKernPairData* ) { - // write entry tag - rpDest[ 0] = (char)(eFCC >> 24); - rpDest[ 1] = (char)(eFCC >> 16); - rpDest[ 2] = (char)(eFCC >> 8); - rpDest[ 3] = (char)(eFCC >> 0); - // TODO: get entry checksum and write it - // not too important since the subsetter doesn't care currently - // for( pData+nOfs ... pData+nOfs+nLen ) - // write entry offset - rpDest[ 8] = (char)(nOfs >> 24); - rpDest[ 9] = (char)(nOfs >> 16); - rpDest[10] = (char)(nOfs >> 8); - rpDest[11] = (char)(nOfs >> 0); - // write entry length - rpDest[12] = (char)(nLen >> 24); - rpDest[13] = (char)(nLen >> 16); - rpDest[14] = (char)(nLen >> 8); - rpDest[15] = (char)(nLen >> 0); - // advance to next entry - rpDest += 16; + return 0; } -#endif - -static bool GetRawFontData( const ImplFontData* /*pFontData*/, - ByteVector& /*rBuffer*/, - bool* /*pJustCFF*/ ) +bool IosSalGraphics::GetImplFontCapabilities(vcl::FontCapabilities &rFontCapabilities) const { -#if 0 - const ImplIosFontData* pIosFont = static_cast<const ImplIosFontData*>(pFontData); - const ATSUFontID nFontId = static_cast<ATSUFontID>(pIosFont->GetFontId()); - ATSFontRef rFont = FMGetATSFontRefFromFont( nFontId ); - - ByteCount nCffLen = 0; - OSStatus eStatus = ATSFontGetTable( rFont, GetTag("CFF "), 0, 0, NULL, &nCffLen); - if( pJustCFF != NULL ) + if( !m_pCoreTextFontData ) { - *pJustCFF = (eStatus == noErr) && (nCffLen > 0); - if( *pJustCFF ) - { - rBuffer.resize( nCffLen ); - eStatus = ATSFontGetTable( rFont, GetTag("CFF "), 0, nCffLen, (void*)&rBuffer[0], &nCffLen); - if( (eStatus != noErr) || (nCffLen <= 0) ) - return false; - return true; - } - } - - // get font table availability and size in bytes - ByteCount nHeadLen = 0; - eStatus = ATSFontGetTable( rFont, GetTag("head"), 0, 0, NULL, &nHeadLen); - if( (eStatus != noErr) || (nHeadLen <= 0) ) - return false; - ByteCount nMaxpLen = 0; - eStatus = ATSFontGetTable( rFont, GetTag("maxp"), 0, 0, NULL, &nMaxpLen); - if( (eStatus != noErr) || (nMaxpLen <= 0) ) return false; - ByteCount nCmapLen = 0; - eStatus = ATSFontGetTable( rFont, GetTag("cmap"), 0, 0, NULL, &nCmapLen); - if( (eStatus != noErr) || (nCmapLen <= 0) ) - return false; - ByteCount nNameLen = 0; - eStatus = ATSFontGetTable( rFont, GetTag("name"), 0, 0, NULL, &nNameLen); - if( (eStatus != noErr) || (nNameLen <= 0) ) - return false; - ByteCount nHheaLen = 0; - eStatus = ATSFontGetTable( rFont, GetTag("hhea"), 0, 0, NULL, &nHheaLen); - if( (eStatus != noErr) || (nHheaLen <= 0) ) - return false; - ByteCount nHmtxLen = 0; - eStatus = ATSFontGetTable( rFont, GetTag("hmtx"), 0, 0, NULL, &nHmtxLen); - if( (eStatus != noErr) || (nHmtxLen <= 0) ) - return false; - - // get the glyph outline tables - ByteCount nLocaLen = 0; - ByteCount nGlyfLen = 0; - if( (eStatus != noErr) || (nCffLen <= 0) ) - { - eStatus = ATSFontGetTable( rFont, GetTag("loca"), 0, 0, NULL, &nLocaLen); - if( (eStatus != noErr) || (nLocaLen <= 0) ) - return false; - eStatus = ATSFontGetTable( rFont, GetTag("glyf"), 0, 0, NULL, &nGlyfLen); - if( (eStatus != noErr) || (nGlyfLen <= 0) ) - return false; - } - - ByteCount nPrepLen=0, nCvtLen=0, nFpgmLen=0; - if( nGlyfLen ) // TODO: reduce PDF size by making hint subsetting optional - { - eStatus = ATSFontGetTable( rFont, GetTag("prep"), 0, 0, NULL, &nPrepLen); - eStatus = ATSFontGetTable( rFont, GetTag("cvt "), 0, 0, NULL, &nCvtLen); - eStatus = ATSFontGetTable( rFont, GetTag("fpgm"), 0, 0, NULL, &nFpgmLen); - } - - // prepare a byte buffer for a fake font - int nTableCount = 7; - nTableCount += (nPrepLen>0) + (nCvtLen>0) + (nFpgmLen>0) + (nGlyfLen>0); - const ByteCount nFdirLen = 12 + 16*nTableCount; - ByteCount nTotalLen = nFdirLen; - nTotalLen += nHeadLen + nMaxpLen + nNameLen + nCmapLen; - if( nGlyfLen ) - nTotalLen += nLocaLen + nGlyfLen; - else - nTotalLen += nCffLen; - nTotalLen += nHheaLen + nHmtxLen; - nTotalLen += nPrepLen + nCvtLen + nFpgmLen; - rBuffer.resize( nTotalLen ); - - // fake a SFNT font directory header - if( nTableCount < 16 ) - { - int nLog2 = 0; - while( (nTableCount >> nLog2) > 1 ) ++nLog2; - rBuffer[ 1] = 1; // Win-TTF style scaler - rBuffer[ 5] = nTableCount; // table count - rBuffer[ 7] = nLog2*16; // searchRange - rBuffer[ 9] = nLog2; // entrySelector - rBuffer[11] = (nTableCount-nLog2)*16; // rangeShift - } - - // get font table raw data and update the fake directory entries - ByteCount nOfs = nFdirLen; - unsigned char* pFakeEntry = &rBuffer[12]; - eStatus = ATSFontGetTable( rFont, GetTag("cmap"), 0, nCmapLen, (void*)&rBuffer[nOfs], &nCmapLen); - FakeDirEntry( GetTag("cmap"), nOfs, nCmapLen, &rBuffer[0], pFakeEntry ); - nOfs += nCmapLen; - if( nCvtLen ) { - eStatus = ATSFontGetTable( rFont, GetTag("cvt "), 0, nCvtLen, (void*)&rBuffer[nOfs], &nCvtLen); - FakeDirEntry( GetTag("cvt "), nOfs, nCvtLen, &rBuffer[0], pFakeEntry ); - nOfs += nCvtLen; } - if( nFpgmLen ) { - eStatus = ATSFontGetTable( rFont, GetTag("fpgm"), 0, nFpgmLen, (void*)&rBuffer[nOfs], &nFpgmLen); - FakeDirEntry( GetTag("fpgm"), nOfs, nFpgmLen, &rBuffer[0], pFakeEntry ); - nOfs += nFpgmLen; - } - if( nCffLen ) { - eStatus = ATSFontGetTable( rFont, GetTag("CFF "), 0, nCffLen, (void*)&rBuffer[nOfs], &nCffLen); - FakeDirEntry( GetTag("CFF "), nOfs, nCffLen, &rBuffer[0], pFakeEntry ); - nOfs += nGlyfLen; - } else { - eStatus = ATSFontGetTable( rFont, GetTag("glyf"), 0, nGlyfLen, (void*)&rBuffer[nOfs], &nGlyfLen); - FakeDirEntry( GetTag("glyf"), nOfs, nGlyfLen, &rBuffer[0], pFakeEntry ); - nOfs += nGlyfLen; - eStatus = ATSFontGetTable( rFont, GetTag("loca"), 0, nLocaLen, (void*)&rBuffer[nOfs], &nLocaLen); - FakeDirEntry( GetTag("loca"), nOfs, nLocaLen, &rBuffer[0], pFakeEntry ); - nOfs += nLocaLen; - } - eStatus = ATSFontGetTable( rFont, GetTag("head"), 0, nHeadLen, (void*)&rBuffer[nOfs], &nHeadLen); - FakeDirEntry( GetTag("head"), nOfs, nHeadLen, &rBuffer[0], pFakeEntry ); - nOfs += nHeadLen; - eStatus = ATSFontGetTable( rFont, GetTag("hhea"), 0, nHheaLen, (void*)&rBuffer[nOfs], &nHheaLen); - FakeDirEntry( GetTag("hhea"), nOfs, nHheaLen, &rBuffer[0], pFakeEntry ); - nOfs += nHheaLen; - eStatus = ATSFontGetTable( rFont, GetTag("hmtx"), 0, nHmtxLen, (void*)&rBuffer[nOfs], &nHmtxLen); - FakeDirEntry( GetTag("hmtx"), nOfs, nHmtxLen, &rBuffer[0], pFakeEntry ); - nOfs += nHmtxLen; - eStatus = ATSFontGetTable( rFont, GetTag("maxp"), 0, nMaxpLen, (void*)&rBuffer[nOfs], &nMaxpLen); - FakeDirEntry( GetTag("maxp"), nOfs, nMaxpLen, &rBuffer[0], pFakeEntry ); - nOfs += nMaxpLen; - eStatus = ATSFontGetTable( rFont, GetTag("name"), 0, nNameLen, (void*)&rBuffer[nOfs], &nNameLen); - FakeDirEntry( GetTag("name"), nOfs, nNameLen, &rBuffer[0], pFakeEntry ); - nOfs += nNameLen; - if( nPrepLen ) { - eStatus = ATSFontGetTable( rFont, GetTag("prep"), 0, nPrepLen, (void*)&rBuffer[nOfs], &nPrepLen); - FakeDirEntry( GetTag("prep"), nOfs, nPrepLen, &rBuffer[0], pFakeEntry ); - nOfs += nPrepLen; - } - - DBG_ASSERT( (nOfs==nTotalLen), "IosSalGraphics::CreateFontSubset (nOfs!=nTotalLen)"); -#endif - return sal_True; + return m_pCoreTextFontData->GetImplFontCapabilities(rFontCapabilities); } -sal_Bool IosSalGraphics::CreateFontSubset( const rtl::OUString& rToFile, - const ImplFontData* pFontData, long* pGlyphIDs, sal_uInt8* pEncoding, - sal_Int32* pGlyphWidths, int nGlyphCount, FontSubsetInfo& rInfo ) +const ImplFontCharMap* IosSalGraphics::GetImplFontCharMap() const { - // TODO: move more of the functionality here into the generic subsetter code - - // prepare the requested file name for writing the font-subset file - rtl::OUString aSysPath; - if( osl_File_E_None != osl_getSystemPathFromFileURL( rToFile.pData, &aSysPath.pData ) ) - return sal_False; - const rtl_TextEncoding aThreadEncoding = osl_getThreadTextEncoding(); - const rtl::OString aToFile( rtl::OUStringToOString( aSysPath, aThreadEncoding ) ); - - // get the raw-bytes from the font to be subset - ByteVector aBuffer; - bool bCffOnly = false; - if( !GetRawFontData( pFontData, aBuffer, &bCffOnly ) ) - return sal_False; - - // handle CFF-subsetting - if( bCffOnly ) - { - // provide the raw-CFF data to the subsetter - ByteCount nCffLen = aBuffer.size(); - rInfo.LoadFont( FontSubsetInfo::CFF_FONT, &aBuffer[0], nCffLen ); - - // NOTE: assuming that all glyphids requested on Ios are fully translated - - // make the subsetter provide the requested subset - FILE* pOutFile = fopen( aToFile.getStr(), "wb" ); - bool bRC = rInfo.CreateFontSubset( FontSubsetInfo::TYPE1_PFB, pOutFile, NULL, - pGlyphIDs, pEncoding, nGlyphCount, pGlyphWidths ); - fclose( pOutFile ); - return bRC; - } - - // TODO: modernize psprint's horrible fontsubset C-API - // this probably only makes sense after the switch to another SCM - // that can preserve change history after file renames - - // prepare data for psprint's font subsetter - TrueTypeFont* pSftFont = NULL; - int nRC = ::OpenTTFontBuffer( (void*)&aBuffer[0], aBuffer.size(), 0, &pSftFont); - if( nRC != SF_OK ) - return sal_False; - - // get details about the subsetted font - TTGlobalFontInfo aTTInfo; - ::GetTTGlobalFontInfo( pSftFont, &aTTInfo ); - rInfo.m_nFontType = FontSubsetInfo::SFNT_TTF; - rInfo.m_aPSName = String( aTTInfo.psname, RTL_TEXTENCODING_UTF8 ); - rInfo.m_aFontBBox = Rectangle( Point( aTTInfo.xMin, aTTInfo.yMin ), - Point( aTTInfo.xMax, aTTInfo.yMax ) ); - rInfo.m_nCapHeight = aTTInfo.yMax; // Well ... - rInfo.m_nAscent = +aTTInfo.winAscent; - rInfo.m_nDescent = -aTTInfo.winDescent; - // mac fonts usually do not have an OS2-table - // => get valid ascent/descent values from other tables - if( !rInfo.m_nAscent ) - rInfo.m_nAscent = +aTTInfo.typoAscender; - if( !rInfo.m_nAscent ) - rInfo.m_nAscent = +aTTInfo.ascender; - if( !rInfo.m_nDescent ) - rInfo.m_nDescent = +aTTInfo.typoDescender; - if( !rInfo.m_nDescent ) - rInfo.m_nDescent = -aTTInfo.descender; - - // subset glyphs and get their properties - // take care that subset fonts require the NotDef glyph in pos 0 - int nOrigCount = nGlyphCount; - sal_uInt16 aShortIDs[ 256 ]; - sal_uInt8 aTempEncs[ 256 ]; - - int nNotDef = -1; - for( int i = 0; i < nGlyphCount; ++i ) + if( !m_pCoreTextFontData ) { - aTempEncs[i] = pEncoding[i]; - sal_uInt32 nGlyphIdx = pGlyphIDs[i] & GF_IDXMASK; - if( pGlyphIDs[i] & GF_ISCHAR ) - { - bool bVertical = (pGlyphIDs[i] & GF_ROTMASK) != 0; - nGlyphIdx = ::MapChar( pSftFont, static_cast<sal_uInt16>(nGlyphIdx), bVertical ); - if( nGlyphIdx == 0 && pFontData->IsSymbolFont() ) - { - // #i12824# emulate symbol aliasing U+FXXX <-> U+0XXX - nGlyphIdx = pGlyphIDs[i] & GF_IDXMASK; - nGlyphIdx = (nGlyphIdx & 0xF000) ? (nGlyphIdx & 0x00FF) : (nGlyphIdx | 0xF000 ); - nGlyphIdx = ::MapChar( pSftFont, static_cast<sal_uInt16>(nGlyphIdx), bVertical ); - } - } - aShortIDs[i] = static_cast<sal_uInt16>( nGlyphIdx ); - if( !nGlyphIdx ) - if( nNotDef < 0 ) - nNotDef = i; // first NotDef glyph found - } - - if( nNotDef != 0 ) - { - // add fake NotDef glyph if needed - if( nNotDef < 0 ) - nNotDef = nGlyphCount++; - - // NotDef glyph must be in pos 0 => swap glyphids - aShortIDs[ nNotDef ] = aShortIDs[0]; - aTempEncs[ nNotDef ] = aTempEncs[0]; - aShortIDs[0] = 0; - aTempEncs[0] = 0; + return ImplFontCharMap::GetDefaultMap(); } - DBG_ASSERT( nGlyphCount < 257, "too many glyphs for subsetting" ); - - // TODO: where to get bVertical? - const bool bVertical = false; - - // fill the pGlyphWidths array - // while making sure that the NotDef glyph is at index==0 - TTSimpleGlyphMetrics* pGlyphMetrics = - ::GetTTSimpleGlyphMetrics( pSftFont, aShortIDs, nGlyphCount, bVertical ); - if( !pGlyphMetrics ) - return sal_False; - sal_uInt16 nNotDefAdv = pGlyphMetrics[0].adv; - pGlyphMetrics[0].adv = pGlyphMetrics[nNotDef].adv; - pGlyphMetrics[nNotDef].adv = nNotDefAdv; - for( int i = 0; i < nOrigCount; ++i ) - pGlyphWidths[i] = pGlyphMetrics[i].adv; - free( pGlyphMetrics ); - - // write subset into destination file - nRC = ::CreateTTFromTTGlyphs( pSftFont, aToFile.getStr(), aShortIDs, - aTempEncs, nGlyphCount, 0, NULL, 0 ); - ::CloseTTFont(pSftFont); - return (nRC == SF_OK); + return m_pCoreTextFontData->GetImplFontCharMap(); } -// ----------------------------------------------------------------------- - -void IosSalGraphics::GetGlyphWidths( const ImplFontData* pFontData, bool bVertical, - Int32Vector& rGlyphWidths, Ucs2UIntMap& rUnicodeEnc ) +bool IosSalGraphics::GetRawFontData( const ImplFontData* pFontData, + std::vector<unsigned char>& rBuffer, bool* pJustCFF ) { - rGlyphWidths.clear(); - rUnicodeEnc.clear(); - - if( pFontData->IsSubsettable() ) - { - ByteVector aBuffer; - if( !GetRawFontData( pFontData, aBuffer, NULL ) ) - return; - - // TODO: modernize psprint's horrible fontsubset C-API - // this probably only makes sense after the switch to another SCM - // that can preserve change history after file renames - - // use the font subsetter to get the widths - TrueTypeFont* pSftFont = NULL; - int nRC = ::OpenTTFontBuffer( (void*)&aBuffer[0], aBuffer.size(), 0, &pSftFont); - if( nRC != SF_OK ) - return; - - const int nGlyphCount = ::GetTTGlyphCount( pSftFont ); - if( nGlyphCount > 0 ) - { - // get glyph metrics - rGlyphWidths.resize(nGlyphCount); - std::vector<sal_uInt16> aGlyphIds(nGlyphCount); - for( int i = 0; i < nGlyphCount; i++ ) - aGlyphIds[i] = static_cast<sal_uInt16>(i); - const TTSimpleGlyphMetrics* pGlyphMetrics = ::GetTTSimpleGlyphMetrics( - pSftFont, &aGlyphIds[0], nGlyphCount, bVertical ); - if( pGlyphMetrics ) - { - for( int i = 0; i < nGlyphCount; ++i ) - rGlyphWidths[i] = pGlyphMetrics[i].adv; - free( (void*)pGlyphMetrics ); - } - - const ImplFontCharMap* pMap = mpIosFontData->GetImplFontCharMap(); - DBG_ASSERT( pMap && pMap->GetCharCount(), "no charmap" ); - pMap->AddReference(); // TODO: add and use RAII object instead - - // get unicode<->glyph encoding - // TODO? avoid sft mapping by using the pMap itself - int nCharCount = pMap->GetCharCount(); - sal_uInt32 nChar = pMap->GetFirstChar(); - for(; --nCharCount >= 0; nChar = pMap->GetNextChar( nChar ) ) - { - if( nChar > 0xFFFF ) // TODO: allow UTF-32 chars - break; - sal_Ucs nUcsChar = static_cast<sal_Ucs>(nChar); - sal_uInt32 nGlyph = ::MapChar( pSftFont, nUcsChar, bVertical ); - if( nGlyph > 0 ) - rUnicodeEnc[ nUcsChar ] = nGlyph; - } + const ImplCoreTextFontData* font_data = static_cast<const ImplCoreTextFontData*>(pFontData); - pMap->DeReference(); // TODO: add and use RAII object instead - } - - ::CloseTTFont( pSftFont ); - } - else if( pFontData->IsEmbeddable() ) - { - // get individual character widths - OSL_FAIL("not implemented for non-subsettable fonts!\n"); - } -} - -// ----------------------------------------------------------------------- - -const Ucs2SIntMap* IosSalGraphics::GetFontEncodingVector( - const ImplFontData*, const Ucs2OStrMap** /*ppNonEncoded*/ ) -{ - return NULL; + return font_data->GetRawFontData(rBuffer, pJustCFF); } -// ----------------------------------------------------------------------- - -const void* IosSalGraphics::GetEmbedFontData( const ImplFontData*, - const sal_Ucs* /*pUnicodes*/, - sal_Int32* /*pWidths*/, - FontSubsetInfo&, - long* /*pDataLen*/ ) -{ - return NULL; -} - -// ----------------------------------------------------------------------- - -void IosSalGraphics::FreeEmbedFontData( const void* pData, long /*nDataLen*/ ) -{ - // TODO: implementing this only makes sense when the implementation of - // IosSalGraphics::GetEmbedFontData() returns non-NULL - (void)pData; - DBG_ASSERT( (pData!=NULL), "IosSalGraphics::FreeEmbedFontData() is not implemented\n"); -} - -// ----------------------------------------------------------------------- - SystemFontData IosSalGraphics::GetSysFontData( int /* nFallbacklevel */ ) const { + msgs_debug(gr,"-->"); SystemFontData aSysFontData; aSysFontData.nSize = sizeof( SystemFontData ); - -#if 0 - OSStatus err; - - // NOTE: Native ATSU font fallbacks are used, not the VCL fallbacks. - ATSUFontID fontId; - err = ATSUGetAttribute( maATSUStyle, kATSUFontTag, sizeof(fontId), &fontId, 0 ); - if (err) fontId = 0; - aSysFontData.aATSUFontID = (void *) fontId; - - Boolean bFbold; - err = ATSUGetAttribute( maATSUStyle, kATSUQDBoldfaceTag, sizeof(bFbold), &bFbold, 0 ); - if (err) bFbold = FALSE; - aSysFontData.bFakeBold = (bool) bFbold; - - Boolean bFItalic; - err = ATSUGetAttribute( maATSUStyle, kATSUQDItalicTag, sizeof(bFItalic), &bFItalic, 0 ); - if (err) bFItalic = FALSE; - aSysFontData.bFakeItalic = (bool) bFItalic; - - ATSUVerticalCharacterType aVerticalCharacterType; - err = ATSUGetAttribute( maATSUStyle, kATSUVerticalCharacterTag, sizeof(aVerticalCharacterType), &aVerticalCharacterType, 0 ); - if (!err && aVerticalCharacterType == kATSUStronglyVertical) { - aSysFontData.bVerticalCharacterType = true; - } else { - aSysFontData.bVerticalCharacterType = false; - } - - aSysFontData.bAntialias = !mbNonAntialiasedText; -#endif + aSysFontData.bAntialias = true; + + CTFontRef font = CTFontCreateUIFontForLanguage(kCTFontSystemFontType, 0.0, NULL); + font = (CTFontRef)CFRetain(font); + aSysFontData.rCTFont = (void*)font; + + CTFontRef italic_font = CTFontCreateCopyWithSymbolicTraits( font, + 0.0, + NULL, + kCTFontItalicTrait, + kCTFontItalicTrait + kCTFontBoldTrait); + aSysFontData.bFakeItalic = italic_font ? false : true; + SafeCFRelease(italic_font); + + CTFontRef bold_font = CTFontCreateCopyWithSymbolicTraits( font, + 0.0, + NULL, + kCTFontBoldTrait, + kCTFontItalicTrait + kCTFontBoldTrait); + aSysFontData.bFakeBold = bold_font ? false : true; + SafeCFRelease(bold_font); + + CTFontRef vertical_font = CTFontCreateCopyWithSymbolicTraits( font, + 0.0, + NULL, + kCTFontVerticalTrait, + kCTFontVerticalTrait); + aSysFontData.bVerticalCharacterType = vertical_font ? true : false; + SafeCFRelease(vertical_font); + + msgs_debug(gr,"<--"); return aSysFontData; } -// ----------------------------------------------------------------------- - -SystemGraphicsData IosSalGraphics::GetGraphicsData() const +SalLayout* IosSalGraphics::GetTextLayout( ImplLayoutArgs&, int /*nFallbackLevel*/ ) { - SystemGraphicsData aRes; - aRes.nSize = sizeof(aRes); - aRes.rCGContext = mrContext; - return aRes; + msgs_debug(gr,"-->"); + CoreTextLayout* layout = new CoreTextLayout( this, m_style ); + msgs_debug(gr,"layout:%p <--", layout); + return layout; } -// ----------------------------------------------------------------------- - -void IosSalGraphics::SetXORMode( bool bSet, bool bInvertOnly ) -{ - // return early if XOR mode remains unchanged - if( mbPrinter ) - return; - - if( ! bSet && mnXorMode == 2 ) - { - CGContextSetBlendMode( mrContext, kCGBlendModeNormal ); - mnXorMode = 0; - return; - } - else if( bSet && bInvertOnly && mnXorMode == 0) - { - CGContextSetBlendMode( mrContext, kCGBlendModeDifference ); - mnXorMode = 2; - return; - } - - if( (mpXorEmulation == NULL) && !bSet ) - return; - if( (mpXorEmulation != NULL) && (bSet == mpXorEmulation->IsEnabled()) ) - return; - if( !CheckContext() ) - return; - - // prepare XOR emulation - if( !mpXorEmulation ) - { - mpXorEmulation = new XorEmulation(); - mpXorEmulation->SetTarget( mnWidth, mnHeight, mnBitmapDepth, mrContext, mxLayer ); - } - - // change the XOR mode - if( bSet ) - { - mpXorEmulation->Enable(); - mrContext = mpXorEmulation->GetMaskContext(); - mnXorMode = 1; - } - else - { - mpXorEmulation->UpdateTarget(); - mpXorEmulation->Disable(); - mrContext = mpXorEmulation->GetTargetContext(); - mnXorMode = 0; - } -} - -// ----------------------------------------------------------------------- - -// apply the XOR mask to the target context if active and dirty -void IosSalGraphics::ApplyXorContext() -{ - if( !mpXorEmulation ) - return; - if( mpXorEmulation->UpdateTarget() ) - RefreshRect( 0, 0, mnWidth, mnHeight ); // TODO: refresh minimal changerect -} - -// ====================================================================== - -XorEmulation::XorEmulation() -: mxTargetLayer( NULL ) -, mxTargetContext( NULL ) -, mxMaskContext( NULL ) -, mxTempContext( NULL ) -, mpMaskBuffer( NULL ) -, mpTempBuffer( NULL ) -, mnBufferLongs( 0 ) -, mbIsEnabled( false ) -{} - -// ---------------------------------------------------------------------- - -XorEmulation::~XorEmulation() -{ - Disable(); - SetTarget( 0, 0, 0, NULL, NULL ); -} - -// ----------------------------------------------------------------------- - -void XorEmulation::SetTarget( int nWidth, int nHeight, int nTargetDepth, - CGContextRef xTargetContext, CGLayerRef xTargetLayer ) +sal_uInt16 IosSalGraphics::SetFont( FontSelectPattern* pReqFont, int /*nFallbackLevel*/ ) { - // prepare to replace old mask+temp context - if( mxMaskContext ) - { - // cleanup the mask context - CGContextRelease( mxMaskContext ); - delete[] mpMaskBuffer; - mxMaskContext = NULL; - mpMaskBuffer = NULL; - - // cleanup the temp context if needed - if( mxTempContext ) - { - CGContextRelease( mxTempContext ); - delete[] mpTempBuffer; - mxTempContext = NULL; - mpTempBuffer = NULL; - } - } - - // return early if there is nothing more to do - if( !xTargetContext ) - return; - - // retarget drawing operations to the XOR mask - mxTargetLayer = xTargetLayer; - mxTargetContext = xTargetContext; - - // prepare creation of matching CGBitmaps - CGColorSpaceRef aCGColorSpace = GetSalData()->mxRGBSpace; - CGBitmapInfo aCGBmpInfo = kCGImageAlphaNoneSkipFirst; - int nBitDepth = nTargetDepth; - if( !nBitDepth ) - nBitDepth = 32; - int nBytesPerRow = (nBitDepth == 16) ? 2 : 4; - const size_t nBitsPerComponent = (nBitDepth == 16) ? 5 : 8; - if( nBitDepth <= 8 ) - { - aCGColorSpace = GetSalData()->mxGraySpace; - aCGBmpInfo = kCGImageAlphaNone; - nBytesPerRow = 1; - } - nBytesPerRow *= nWidth; - mnBufferLongs = (nHeight * nBytesPerRow + sizeof(sal_uLong)-1) / sizeof(sal_uLong); - - // create a XorMask context - mpMaskBuffer = new sal_uLong[ mnBufferLongs ]; - mxMaskContext = ::CGBitmapContextCreate( mpMaskBuffer, - nWidth, nHeight, nBitsPerComponent, nBytesPerRow, - aCGColorSpace, aCGBmpInfo ); - // reset the XOR mask to black - memset( mpMaskBuffer, 0, mnBufferLongs * sizeof(sal_uLong) ); - - // a bitmap context will be needed for manual XORing - // create one unless the target context is a bitmap context - if( nTargetDepth ) - mpTempBuffer = (sal_uLong*)CGBitmapContextGetData( mxTargetContext ); - if( !mpTempBuffer ) - { - // create a bitmap context matching to the target context - mpTempBuffer = new sal_uLong[ mnBufferLongs ]; - mxTempContext = ::CGBitmapContextCreate( mpTempBuffer, - nWidth, nHeight, nBitsPerComponent, nBytesPerRow, - aCGColorSpace, aCGBmpInfo ); - } - - // initialize XOR mask context for drawing - CGContextSetFillColorSpace( mxMaskContext, aCGColorSpace ); - CGContextSetStrokeColorSpace( mxMaskContext, aCGColorSpace ); - CGContextSetShouldAntialias( mxMaskContext, false ); - - // improve the XorMask's XOR emulation a litte - // NOTE: currently only enabled for monochrome contexts - if( aCGColorSpace == GetSalData()->mxGraySpace ) - CGContextSetBlendMode( mxMaskContext, kCGBlendModeDifference ); - - // intialize the transformation matrix to the drawing target - const CGAffineTransform aCTM = CGContextGetCTM( xTargetContext ); - CGContextConcatCTM( mxMaskContext, aCTM ); - if( mxTempContext ) - CGContextConcatCTM( mxTempContext, aCTM ); - - // initialize the default XorMask graphics state - CGContextSaveGState( mxMaskContext ); + msgs_debug(gr,"m_style=%p -->", m_style); + m_style->SetFont(pReqFont); + msgs_debug(gr,"<--"); + return 0; } -// ---------------------------------------------------------------------- - -bool XorEmulation::UpdateTarget() +void IosSalGraphics::SetTextColor( SalColor nSalColor ) { - if( !IsEnabled() ) - return false; - - // update the temp bitmap buffer if needed - if( mxTempContext ) - CGContextDrawLayerAtPoint( mxTempContext, CGPointZero, mxTargetLayer ); - - // do a manual XOR with the XorMask - // this approach suffices for simple color manipulations - // and also the complex-clipping-XOR-trick used in metafiles - const sal_uLong* pSrc = mpMaskBuffer; - sal_uLong* pDst = mpTempBuffer; - for( int i = mnBufferLongs; --i >= 0;) - *(pDst++) ^= *(pSrc++); - - // write back the XOR results to the target context - if( mxTempContext ) - { - CGImageRef xXorImage = CGBitmapContextCreateImage( mxTempContext ); - const int nWidth = (int)CGImageGetWidth( xXorImage ); - const int nHeight = (int)CGImageGetHeight( xXorImage ); - // TODO: update minimal changerect - const CGRect aFullRect = {{0,0},{nWidth,nHeight}}; - CGContextDrawImage( mxTargetContext, aFullRect, xXorImage ); - CGImageRelease( xXorImage ); - } - - // reset the XorMask to black again - // TODO: not needed for last update - memset( mpMaskBuffer, 0, mnBufferLongs * sizeof(sal_uLong) ); - - // TODO: return FALSE if target was not changed - return true; + msgs_debug(gr,"m_style=%p -->", m_style); + m_style->SetColor(nSalColor); + msgs_debug(gr,"<--"); } -// ======================================================================= - /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/ios/source/gdi/salgdicommon.cxx b/vcl/ios/source/gdi/salgdicommon.cxx new file mode 100644 index 000000000000..9ceefb2d606b --- /dev/null +++ b/vcl/ios/source/gdi/salgdicommon.cxx @@ -0,0 +1,1581 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include <sal/types.h> +#include <osl/file.hxx> + +#include "basegfx/polygon/b2dpolygon.hxx" + +#include "ios/salbmp.h" +#include "ios/salgdi.h" + +#include "fontsubset.hxx" +#include "region.h" +#include "sft.hxx" + +using namespace vcl; + +//typedef unsigned char Boolean; // copied from MacTypes.h, should be properly included +typedef std::vector<unsigned char> ByteVector; + +static const basegfx::B2DPoint aHalfPointOfs ( 0.5, 0.5 ); + +static void AddPolygonToPath( CGMutablePathRef xPath, + const ::basegfx::B2DPolygon& rPolygon, + bool bClosePath, bool bPixelSnap, bool bLineDraw ) +{ + // short circuit if there is nothing to do + const int nPointCount = rPolygon.count(); + if( nPointCount <= 0 ) + { + return; + } + (void)bPixelSnap; // TODO + const CGAffineTransform* pTransform = NULL; + + const bool bHasCurves = rPolygon.areControlPointsUsed(); + for( int nPointIdx = 0, nPrevIdx = 0;; nPrevIdx = nPointIdx++ ) + { + int nClosedIdx = nPointIdx; + if( nPointIdx >= nPointCount ) + { + // prepare to close last curve segment if needed + if( bClosePath && (nPointIdx == nPointCount) ) + { + nClosedIdx = 0; + } + else + { + break; + } + } + + ::basegfx::B2DPoint aPoint = rPolygon.getB2DPoint( nClosedIdx ); + + if( bPixelSnap) + { + // snap device coordinates to full pixels + aPoint.setX( basegfx::fround( aPoint.getX() ) ); + aPoint.setY( basegfx::fround( aPoint.getY() ) ); + } + + if( bLineDraw ) + { + aPoint += aHalfPointOfs; + } + if( !nPointIdx ) + { + // first point => just move there + CGPathMoveToPoint( xPath, pTransform, aPoint.getX(), aPoint.getY() ); + continue; + } + + bool bPendingCurve = false; + if( bHasCurves ) + { + bPendingCurve = rPolygon.isNextControlPointUsed( nPrevIdx ); + bPendingCurve |= rPolygon.isPrevControlPointUsed( nClosedIdx ); + } + + if( !bPendingCurve ) // line segment + { + CGPathAddLineToPoint( xPath, pTransform, aPoint.getX(), aPoint.getY() ); + } + else // cubic bezier segment + { + basegfx::B2DPoint aCP1 = rPolygon.getNextControlPoint( nPrevIdx ); + basegfx::B2DPoint aCP2 = rPolygon.getPrevControlPoint( nClosedIdx ); + if( bLineDraw ) + { + aCP1 += aHalfPointOfs; + aCP2 += aHalfPointOfs; + } + CGPathAddCurveToPoint( xPath, pTransform, aCP1.getX(), aCP1.getY(), + aCP2.getX(), aCP2.getY(), aPoint.getX(), aPoint.getY() ); + } + } + + if( bClosePath ) + { + CGPathCloseSubpath( xPath ); + } +} + +static void AddPolyPolygonToPath( CGMutablePathRef xPath, + const ::basegfx::B2DPolyPolygon& rPolyPoly, + bool bPixelSnap, bool bLineDraw ) +{ + // short circuit if there is nothing to do + const int nPolyCount = rPolyPoly.count(); + if( nPolyCount <= 0 ) + { + return; + } + for( int nPolyIdx = 0; nPolyIdx < nPolyCount; ++nPolyIdx ) + { + const ::basegfx::B2DPolygon rPolygon = rPolyPoly.getB2DPolygon( nPolyIdx ); + AddPolygonToPath( xPath, rPolygon, true, bPixelSnap, bLineDraw ); + } +} + +sal_Bool IosSalGraphics::CreateFontSubset( const rtl::OUString& rToFile, + const ImplFontData* pFontData, + long* pGlyphIDs, sal_uInt8* pEncoding, + sal_Int32* pGlyphWidths, int nGlyphCount, + FontSubsetInfo& rInfo ) +{ + // TODO: move more of the functionality here into the generic subsetter code + + // prepare the requested file name for writing the font-subset file + rtl::OUString aSysPath; + if( osl_File_E_None != osl_getSystemPathFromFileURL( rToFile.pData, &aSysPath.pData ) ) + return sal_False; + const rtl_TextEncoding aThreadEncoding = osl_getThreadTextEncoding(); + const rtl::OString aToFile( rtl::OUStringToOString( aSysPath, aThreadEncoding ) ); + + // get the raw-bytes from the font to be subset + ByteVector aBuffer; + bool bCffOnly = false; + if( !GetRawFontData( pFontData, aBuffer, &bCffOnly ) ) + return sal_False; + + // handle CFF-subsetting + if( bCffOnly ) + { + // provide the raw-CFF data to the subsetter + ByteCount nCffLen = aBuffer.size(); + rInfo.LoadFont( FontSubsetInfo::CFF_FONT, &aBuffer[0], nCffLen ); + + // NOTE: assuming that all glyphids requested on Ios are fully translated + + // make the subsetter provide the requested subset + FILE* pOutFile = fopen( aToFile.getStr(), "wb" ); + bool bRC = rInfo.CreateFontSubset( FontSubsetInfo::TYPE1_PFB, pOutFile, NULL, + pGlyphIDs, pEncoding, nGlyphCount, pGlyphWidths ); + fclose( pOutFile ); + return bRC; + } + + // TODO: modernize psprint's horrible fontsubset C-API + // this probably only makes sense after the switch to another SCM + // that can preserve change history after file renames + + // prepare data for psprint's font subsetter + TrueTypeFont* pSftFont = NULL; + int nRC = ::OpenTTFontBuffer( (void*)&aBuffer[0], aBuffer.size(), 0, &pSftFont); + if( nRC != SF_OK ) + return sal_False; + + // get details about the subsetted font + TTGlobalFontInfo aTTInfo; + ::GetTTGlobalFontInfo( pSftFont, &aTTInfo ); + rInfo.m_nFontType = FontSubsetInfo::SFNT_TTF; + rInfo.m_aPSName = String( aTTInfo.psname, RTL_TEXTENCODING_UTF8 ); + rInfo.m_aFontBBox = Rectangle( Point( aTTInfo.xMin, aTTInfo.yMin ), + Point( aTTInfo.xMax, aTTInfo.yMax ) ); + rInfo.m_nCapHeight = aTTInfo.yMax; // Well ... + rInfo.m_nAscent = aTTInfo.winAscent; + rInfo.m_nDescent = aTTInfo.winDescent; + // mac fonts usually do not have an OS2-table + // => get valid ascent/descent values from other tables + if( !rInfo.m_nAscent ) + rInfo.m_nAscent = +aTTInfo.typoAscender; + if( !rInfo.m_nAscent ) + rInfo.m_nAscent = +aTTInfo.ascender; + if( !rInfo.m_nDescent ) + rInfo.m_nDescent = +aTTInfo.typoDescender; + if( !rInfo.m_nDescent ) + rInfo.m_nDescent = -aTTInfo.descender; + + // subset glyphs and get their properties + // take care that subset fonts require the NotDef glyph in pos 0 + int nOrigCount = nGlyphCount; + sal_uInt16 aShortIDs[ 256 ]; + sal_uInt8 aTempEncs[ 256 ]; + + int nNotDef = -1; + for( int i = 0; i < nGlyphCount; ++i ) + { + aTempEncs[i] = pEncoding[i]; + sal_uInt32 nGlyphIdx = pGlyphIDs[i] & GF_IDXMASK; + if( pGlyphIDs[i] & GF_ISCHAR ) + { + bool bVertical = (pGlyphIDs[i] & GF_ROTMASK) != 0; + nGlyphIdx = ::MapChar( pSftFont, static_cast<sal_uInt16>(nGlyphIdx), bVertical ); + if( nGlyphIdx == 0 && pFontData->IsSymbolFont() ) + { + // #i12824# emulate symbol aliasing U+FXXX <-> U+0XXX + nGlyphIdx = pGlyphIDs[i] & GF_IDXMASK; + nGlyphIdx = (nGlyphIdx & 0xF000) ? (nGlyphIdx & 0x00FF) : (nGlyphIdx | 0xF000 ); + nGlyphIdx = ::MapChar( pSftFont, static_cast<sal_uInt16>(nGlyphIdx), bVertical ); + } + } + aShortIDs[i] = static_cast<sal_uInt16>( nGlyphIdx ); + if( !nGlyphIdx ) + if( nNotDef < 0 ) + nNotDef = i; // first NotDef glyph found + } + + if( nNotDef != 0 ) + { + // add fake NotDef glyph if needed + if( nNotDef < 0 ) + nNotDef = nGlyphCount++; + + // NotDef glyph must be in pos 0 => swap glyphids + aShortIDs[ nNotDef ] = aShortIDs[0]; + aTempEncs[ nNotDef ] = aTempEncs[0]; + aShortIDs[0] = 0; + aTempEncs[0] = 0; + } + DBG_ASSERT( nGlyphCount < 257, "too many glyphs for subsetting" ); + + // TODO: where to get bVertical? + const bool bVertical = false; + + // fill the pGlyphWidths array + // while making sure that the NotDef glyph is at index==0 + TTSimpleGlyphMetrics* pGlyphMetrics = + ::GetTTSimpleGlyphMetrics( pSftFont, aShortIDs, nGlyphCount, bVertical ); + if( !pGlyphMetrics ) + return sal_False; + sal_uInt16 nNotDefAdv = pGlyphMetrics[0].adv; + pGlyphMetrics[0].adv = pGlyphMetrics[nNotDef].adv; + pGlyphMetrics[nNotDef].adv = nNotDefAdv; + for( int i = 0; i < nOrigCount; ++i ) + pGlyphWidths[i] = pGlyphMetrics[i].adv; + free( pGlyphMetrics ); + + // write subset into destination file + nRC = ::CreateTTFromTTGlyphs( pSftFont, aToFile.getStr(), aShortIDs, + aTempEncs, nGlyphCount, 0, NULL, 0 ); + ::CloseTTFont(pSftFont); + return (nRC == SF_OK); +} + +static inline void alignLinePoint( const SalPoint* i_pIn, float& o_fX, float& o_fY ) +{ + o_fX = static_cast<float>(i_pIn->mnX ) + 0.5; + o_fY = static_cast<float>(i_pIn->mnY ) + 0.5; +} + +void IosSalGraphics::copyBits( const SalTwoRect *pPosAry, SalGraphics *pSrcGraphics ) +{ + if( !pSrcGraphics ) + { + pSrcGraphics = this; + } + //from unix salgdi2.cxx + //[FIXME] find a better way to prevent calc from crashing when width and height are negative + if( pPosAry->mnSrcWidth <= 0 + || pPosAry->mnSrcHeight <= 0 + || pPosAry->mnDestWidth <= 0 + || pPosAry->mnDestHeight <= 0 ) + { + return; + } + + // accelerate trivial operations + /*const*/ IosSalGraphics* pSrc = static_cast<IosSalGraphics*>(pSrcGraphics); + const bool bSameGraphics = (this == pSrc) || + (mbWindow && mpFrame && pSrc->mbWindow && (mpFrame == pSrc->mpFrame)); + if( bSameGraphics && + (pPosAry->mnSrcWidth == pPosAry->mnDestWidth) && + (pPosAry->mnSrcHeight == pPosAry->mnDestHeight)) + { + // short circuit if there is nothing to do + if( (pPosAry->mnSrcX == pPosAry->mnDestX) && + (pPosAry->mnSrcY == pPosAry->mnDestY)) + return; + // use copyArea() if source and destination context are identical + copyArea( pPosAry->mnDestX, pPosAry->mnDestY, pPosAry->mnSrcX, pPosAry->mnSrcY, + pPosAry->mnSrcWidth, pPosAry->mnSrcHeight, 0 ); + return; + } + + ApplyXorContext(); + pSrc->ApplyXorContext(); + + DBG_ASSERT( pSrc->mxLayer!=NULL, "IosSalGraphics::copyBits() from non-layered graphics" ); + + const CGPoint aDstPoint = { +pPosAry->mnDestX - pPosAry->mnSrcX, pPosAry->mnDestY - pPosAry->mnSrcY }; + if( (pPosAry->mnSrcWidth == pPosAry->mnDestWidth && + pPosAry->mnSrcHeight == pPosAry->mnDestHeight) && + (!mnBitmapDepth || (aDstPoint.x + pSrc->mnWidth) <= mnWidth) ) // workaround a Quartz crasher + { + // in XOR mode the drawing context is redirected to the XOR mask + // if source and target are identical then copyBits() paints onto the target context though + CGContextRef xCopyContext = mrContext; + if( mpXorEmulation && mpXorEmulation->IsEnabled() ) + { + if( pSrcGraphics == this ) + { + xCopyContext = mpXorEmulation->GetTargetContext(); + } + } + CGContextSaveGState( xCopyContext ); + const CGRect aDstRect = { {pPosAry->mnDestX, pPosAry->mnDestY}, {pPosAry->mnDestWidth, pPosAry->mnDestHeight} }; + CGContextClipToRect( xCopyContext, aDstRect ); + + // draw at new destination + // NOTE: flipped drawing gets disabled for this, else the subimage would be drawn upside down + if( pSrc->IsFlipped() ) + { + CGContextTranslateCTM( xCopyContext, 0, +mnHeight ); CGContextScaleCTM( xCopyContext, +1, -1 ); + } + // TODO: pSrc->size() != this->size() + ::CGContextDrawLayerAtPoint( xCopyContext, aDstPoint, pSrc->mxLayer ); + CGContextRestoreGState( xCopyContext ); + // mark the destination rectangle as updated + RefreshRect( aDstRect ); + } + else + { + SalBitmap* pBitmap = pSrc->getBitmap( pPosAry->mnSrcX, pPosAry->mnSrcY, + pPosAry->mnSrcWidth, pPosAry->mnSrcHeight ); + + if( pBitmap ) + { + SalTwoRect aPosAry( *pPosAry ); + aPosAry.mnSrcX = 0; + aPosAry.mnSrcY = 0; + drawBitmap( &aPosAry, *pBitmap ); + delete pBitmap; + } + } +} + +static void DrawPattern50( void*, CGContextRef rContext ) +{ + static const CGRect aRects[2] = { { {0,0}, { 2, 2 } }, { { 2, 2 }, { 2, 2 } } }; + CGContextAddRects( rContext, aRects, 2 ); + CGContextFillPath( rContext ); +} + +static void getBoundRect( sal_uLong nPoints, const SalPoint *pPtAry, long &rX, long& rY, long& rWidth, long& rHeight ) +{ + long nX1 = pPtAry->mnX; + long nX2 = nX1; + long nY1 = pPtAry->mnY; + long nY2 = nY1; + for( sal_uLong n = 1; n < nPoints; n++ ) + { + if( pPtAry[n].mnX < nX1 ) + { + nX1 = pPtAry[n].mnX; + } + else if( pPtAry[n].mnX > nX2 ) + { + nX2 = pPtAry[n].mnX; + } + if( pPtAry[n].mnY < nY1 ) + { + nY1 = pPtAry[n].mnY; + } + else if( pPtAry[n].mnY > nY2 ) + { + nY2 = pPtAry[n].mnY; + } + } + rX = nX1; + rY = nY1; + rWidth = nX2 - nX1 + 1; + rHeight = nY2 - nY1 + 1; +} + +static SalColor ImplGetROPSalColor( SalROPColor nROPColor ) +{ + SalColor nSalColor; + if ( nROPColor == SAL_ROP_0 ) + { + nSalColor = MAKE_SALCOLOR( 0, 0, 0 ); + } + else + { + nSalColor = MAKE_SALCOLOR( 255, 255, 255 ); + } + return nSalColor; +} + +// apply the XOR mask to the target context if active and dirty +void IosSalGraphics::ApplyXorContext() +{ + if( !mpXorEmulation ) + { + return; + } + if( mpXorEmulation->UpdateTarget() ) + { + RefreshRect( 0, 0, mnWidth, mnHeight ); // TODO: refresh minimal changerect + } +} + +void IosSalGraphics::copyArea( long nDstX, long nDstY,long nSrcX, long nSrcY, + long nSrcWidth, long nSrcHeight, sal_uInt16 /*nFlags*/ ) +{ + ApplyXorContext(); + + DBG_ASSERT( mxLayer!=NULL, "IosSalGraphics::copyArea() for non-layered graphics" ); + + // in XOR mode the drawing context is redirected to the XOR mask + // copyArea() always works on the target context though + CGContextRef xCopyContext = mrContext; + if( mpXorEmulation && mpXorEmulation->IsEnabled() ) + { + xCopyContext = mpXorEmulation->GetTargetContext(); + } + // drawing a layer onto its own context causes trouble on OSX => copy it first + // TODO: is it possible to get rid of this unneeded copy more often? + // e.g. on OSX>=10.5 only this situation causes problems: + // mnBitmapDepth && (aDstPoint.x + pSrc->mnWidth) > mnWidth + CGLayerRef xSrcLayer = mxLayer; + // TODO: if( mnBitmapDepth > 0 ) + { + const CGSize aSrcSize = { nSrcWidth, nSrcHeight }; + xSrcLayer = ::CGLayerCreateWithContext( xCopyContext, aSrcSize, NULL ); + const CGContextRef xSrcContext = CGLayerGetContext( xSrcLayer ); + CGPoint aSrcPoint = { -nSrcX, -nSrcY }; + if( IsFlipped() ) + { + ::CGContextTranslateCTM( xSrcContext, 0, +nSrcHeight ); + ::CGContextScaleCTM( xSrcContext, +1, -1 ); + aSrcPoint.y = (nSrcY + nSrcHeight) - mnHeight; + } + ::CGContextDrawLayerAtPoint( xSrcContext, aSrcPoint, mxLayer ); + } + + // draw at new destination + const CGPoint aDstPoint = { +nDstX, +nDstY }; + ::CGContextDrawLayerAtPoint( xCopyContext, aDstPoint, xSrcLayer ); + + // cleanup + if( xSrcLayer != mxLayer ) + { + CGLayerRelease( xSrcLayer ); + } + // mark the destination rectangle as updated + RefreshRect( nDstX, nDstY, nSrcWidth, nSrcHeight ); + +} + +void IosSalGraphics::copyResolution( IosSalGraphics& rGraphics ) +{ + if( !rGraphics.mnRealDPIY && rGraphics.mbWindow && rGraphics.mpFrame ) + { + rGraphics.initResolution( rGraphics.mpFrame->mpWindow ); + } + mnRealDPIX = rGraphics.mnRealDPIX; + mnRealDPIY = rGraphics.mnRealDPIY; + mfFakeDPIScale = rGraphics.mfFakeDPIScale; +} + +bool IosSalGraphics::drawAlphaBitmap( const SalTwoRect& rTR, + const SalBitmap& rSrcBitmap, + const SalBitmap& rAlphaBmp ) +{ + // An image mask can't have a depth > 8 bits (should be 1 to 8 bits) + if( rAlphaBmp.GetBitCount() > 8 ) + { + return false; + } + // are these two tests really necessary? (see vcl/unx/source/gdi/salgdi2.cxx) + // horizontal/vertical mirroring not implemented yet + if( rTR.mnDestWidth < 0 || rTR.mnDestHeight < 0 ) + { + return false; + } + + const IosSalBitmap& rSrcSalBmp = static_cast<const IosSalBitmap&>(rSrcBitmap); + const IosSalBitmap& rMaskSalBmp = static_cast<const IosSalBitmap&>(rAlphaBmp); + CGImageRef xMaskedImage = rSrcSalBmp.CreateWithMask( rMaskSalBmp, rTR.mnSrcX, + rTR.mnSrcY, rTR.mnSrcWidth, + rTR.mnSrcHeight ); + if( !xMaskedImage ) + { + return false; + } + if ( CheckContext() ) + { + const CGRect aDstRect = {{rTR.mnDestX, rTR.mnDestY}, {rTR.mnDestWidth, rTR.mnDestHeight}}; + CGContextDrawImage( mrContext, aDstRect, xMaskedImage ); + RefreshRect( aDstRect ); + } + + CGImageRelease(xMaskedImage); + return true; +} + +bool IosSalGraphics::drawAlphaRect( long nX, long nY, long nWidth, + long nHeight, sal_uInt8 nTransparency ) +{ + if( !CheckContext() ) + { + return true; + } + // save the current state + CGContextSaveGState( mrContext ); + CGContextSetAlpha( mrContext, (100-nTransparency) * (1.0/100) ); + + CGRect aRect = {{nX,nY},{nWidth-1,nHeight-1}}; + if( IsPenVisible() ) + { + aRect.origin.x += 0.5; + aRect.origin.y += 0.5; + } + + CGContextBeginPath( mrContext ); + CGContextAddRect( mrContext, aRect ); + CGContextDrawPath( mrContext, kCGPathFill ); + + // restore state + CGContextRestoreGState(mrContext); + RefreshRect( aRect ); + return true; +} + +void IosSalGraphics::drawBitmap( const SalTwoRect* pPosAry, const SalBitmap& rSalBitmap ) +{ + if( !CheckContext() ) + { + return; + } + const IosSalBitmap& rBitmap = static_cast<const IosSalBitmap&>(rSalBitmap); + CGImageRef xImage = rBitmap.CreateCroppedImage( (int)pPosAry->mnSrcX, (int)pPosAry->mnSrcY, + (int)pPosAry->mnSrcWidth, (int)pPosAry->mnSrcHeight ); + if( !xImage ) + { + return; + } + const CGRect aDstRect = {{pPosAry->mnDestX, pPosAry->mnDestY}, + {pPosAry->mnDestWidth, pPosAry->mnDestHeight}}; + CGContextDrawImage( mrContext, aDstRect, xImage ); + CGImageRelease( xImage ); + RefreshRect( aDstRect ); +} + +void IosSalGraphics::drawBitmap( const SalTwoRect* pPosAry, const SalBitmap& rSalBitmap,SalColor ) +{ + OSL_FAIL("not implemented for color masking!"); + drawBitmap( pPosAry, rSalBitmap ); +} + +void IosSalGraphics::drawBitmap( const SalTwoRect* pPosAry, const SalBitmap& rSalBitmap, + const SalBitmap& rTransparentBitmap ) +{ + if( !CheckContext() ) + { + return; + } + const IosSalBitmap& rBitmap = static_cast<const IosSalBitmap&>(rSalBitmap); + const IosSalBitmap& rMask = static_cast<const IosSalBitmap&>(rTransparentBitmap); + CGImageRef xMaskedImage( rBitmap.CreateWithMask( rMask, pPosAry->mnSrcX, pPosAry->mnSrcY, + pPosAry->mnSrcWidth, pPosAry->mnSrcHeight ) ); + if( !xMaskedImage ) + { + return; + } + const CGRect aDstRect = {{pPosAry->mnDestX, pPosAry->mnDestY}, + {pPosAry->mnDestWidth, pPosAry->mnDestHeight}}; + CGContextDrawImage( mrContext, aDstRect, xMaskedImage ); + CGImageRelease( xMaskedImage ); + RefreshRect( aDstRect ); +} + +sal_Bool IosSalGraphics::drawEPS( long /*nX*/, long /*nY*/, long /*nWidth*/, long /*nHeight*/, + void* /*pEpsData*/, sal_uLong /*nByteCount*/ ) +{ + return sal_False; +} + +void IosSalGraphics::drawLine( long nX1, long nY1, long nX2, long nY2 ) +{ + if( nX1 == nX2 && nY1 == nY2 ) + { + // #i109453# platform independent code expects at least one pixel to be drawn + drawPixel( nX1, nY1 ); + return; + } + + if( !CheckContext() ) + { + return; + } + CGContextBeginPath( mrContext ); + CGContextMoveToPoint( mrContext, static_cast<float>(nX1)+0.5, static_cast<float>(nY1)+0.5 ); + CGContextAddLineToPoint( mrContext, static_cast<float>(nX2)+0.5, static_cast<float>(nY2)+0.5 ); + CGContextDrawPath( mrContext, kCGPathStroke ); + + Rectangle aRefreshRect( nX1, nY1, nX2, nY2 ); +} + +void IosSalGraphics::drawMask( const SalTwoRect* pPosAry, + const SalBitmap& rSalBitmap, + SalColor nMaskColor ) +{ + if( !CheckContext() ) + { + return; + } + const IosSalBitmap& rBitmap = static_cast<const IosSalBitmap&>(rSalBitmap); + CGImageRef xImage = rBitmap.CreateColorMask( pPosAry->mnSrcX, pPosAry->mnSrcY, + pPosAry->mnSrcWidth, pPosAry->mnSrcHeight, + nMaskColor ); + if( !xImage ) + { + return; + } + const CGRect aDstRect = {{pPosAry->mnDestX, pPosAry->mnDestY}, + {pPosAry->mnDestWidth, pPosAry->mnDestHeight}}; + CGContextDrawImage( mrContext, aDstRect, xImage ); + CGImageRelease( xImage ); + RefreshRect( aDstRect ); +} + +void IosSalGraphics::drawPixel( long nX, long nY ) +{ + // draw pixel with current line color + ImplDrawPixel( nX, nY, maLineColor ); +} + +void IosSalGraphics::drawPixel( long nX, long nY, SalColor nSalColor ) +{ + const RGBAColor aPixelColor( nSalColor ); + ImplDrawPixel( nX, nY, aPixelColor ); +} + +bool IosSalGraphics::drawPolyLine( const ::basegfx::B2DPolygon& rPolyLine, + double fTransparency, + const ::basegfx::B2DVector& rLineWidths, + basegfx::B2DLineJoin eLineJoin ) +{ + // short circuit if there is nothing to do + const int nPointCount = rPolyLine.count(); + if( nPointCount <= 0 ) + { + return true; + } + // reject requests that cannot be handled yet + if( rLineWidths.getX() != rLineWidths.getY() ) + { + return false; + } + // #i101491# Ios does not support B2DLINEJOIN_NONE; return false to use + // the fallback (own geometry preparation) + // #i104886# linejoin-mode and thus the above only applies to "fat" lines + if( (basegfx::B2DLINEJOIN_NONE == eLineJoin) && + (rLineWidths.getX() > 1.3) ) + { + return false; + } + // setup line attributes + CGLineJoin aCGLineJoin = kCGLineJoinMiter; + switch( eLineJoin ) + { + case ::basegfx::B2DLINEJOIN_NONE: aCGLineJoin = /*TODO?*/kCGLineJoinMiter; break; + case ::basegfx::B2DLINEJOIN_MIDDLE: aCGLineJoin = /*TODO?*/kCGLineJoinMiter; break; + case ::basegfx::B2DLINEJOIN_BEVEL: aCGLineJoin = kCGLineJoinBevel; break; + case ::basegfx::B2DLINEJOIN_MITER: aCGLineJoin = kCGLineJoinMiter; break; + case ::basegfx::B2DLINEJOIN_ROUND: aCGLineJoin = kCGLineJoinRound; break; + } + + // setup poly-polygon path + CGMutablePathRef xPath = CGPathCreateMutable(); + AddPolygonToPath( xPath, rPolyLine, rPolyLine.isClosed(), !getAntiAliasB2DDraw(), true ); + + const CGRect aRefreshRect = CGPathGetBoundingBox( xPath ); +#ifndef NO_I97317_WORKAROUND + // #i97317# workaround for Quartz having problems with drawing small polygons + if( ! ((aRefreshRect.size.width <= 0.125) && (aRefreshRect.size.height <= 0.125)) ) +#endif + { + // use the path to prepare the graphics context + CGContextSaveGState( mrContext ); + CGContextAddPath( mrContext, xPath ); + // draw path with antialiased line + CGContextSetShouldAntialias( mrContext, true ); + CGContextSetAlpha( mrContext, 1.0 - fTransparency ); + CGContextSetLineJoin( mrContext, aCGLineJoin ); + CGContextSetLineWidth( mrContext, rLineWidths.getX() ); + CGContextDrawPath( mrContext, kCGPathStroke ); + CGContextRestoreGState( mrContext ); + + // mark modified rectangle as updated + RefreshRect( aRefreshRect ); + } + + CGPathRelease( xPath ); + + return true; +} + +sal_Bool IosSalGraphics::drawPolyLineBezier( sal_uLong, const SalPoint*, const sal_uInt8* ) +{ + return sal_False; +} + +bool IosSalGraphics::drawPolyPolygon( const ::basegfx::B2DPolyPolygon& rPolyPoly, + double fTransparency ) +{ + // short circuit if there is nothing to do + const int nPolyCount = rPolyPoly.count(); + if( nPolyCount <= 0 ) + { + return true; + } + // ignore invisible polygons + if( (fTransparency >= 1.0) || (fTransparency < 0) ) + { + return true; + } + // setup poly-polygon path + CGMutablePathRef xPath = CGPathCreateMutable(); + for( int nPolyIdx = 0; nPolyIdx < nPolyCount; ++nPolyIdx ) + { + const ::basegfx::B2DPolygon rPolygon = rPolyPoly.getB2DPolygon( nPolyIdx ); + AddPolygonToPath( xPath, rPolygon, true, !getAntiAliasB2DDraw(), IsPenVisible() ); + } + + const CGRect aRefreshRect = CGPathGetBoundingBox( xPath ); +#ifndef NO_I97317_WORKAROUND + // #i97317# workaround for Quartz having problems with drawing small polygons + if( ! ((aRefreshRect.size.width <= 0.125) && (aRefreshRect.size.height <= 0.125)) ) +#endif + { + // use the path to prepare the graphics context + CGContextSaveGState( mrContext ); + CGContextBeginPath( mrContext ); + CGContextAddPath( mrContext, xPath ); + + // draw path with antialiased polygon + CGContextSetShouldAntialias( mrContext, true ); + CGContextSetAlpha( mrContext, 1.0 - fTransparency ); + CGContextDrawPath( mrContext, kCGPathEOFillStroke ); + CGContextRestoreGState( mrContext ); + + // mark modified rectangle as updated + RefreshRect( aRefreshRect ); + } + + CGPathRelease( xPath ); + + return true; +} + +void IosSalGraphics::drawPolyPolygon( sal_uLong nPolyCount, const sal_uLong *pPoints, PCONSTSALPOINT *ppPtAry ) +{ + if( nPolyCount <= 0 ) + return; + if( !CheckContext() ) + return; + + // find bound rect + long leftX = 0, topY = 0, maxWidth = 0, maxHeight = 0; + getBoundRect( pPoints[0], ppPtAry[0], leftX, topY, maxWidth, maxHeight ); + for( sal_uLong n = 1; n < nPolyCount; n++ ) + { + long nX = leftX, nY = topY, nW = maxWidth, nH = maxHeight; + getBoundRect( pPoints[n], ppPtAry[n], nX, nY, nW, nH ); + if( nX < leftX ) + { + maxWidth += leftX - nX; + leftX = nX; + } + if( nY < topY ) + { + maxHeight += topY - nY; + topY = nY; + } + if( nX + nW > leftX + maxWidth ) + { + maxWidth = nX + nW - leftX; + } + if( nY + nH > topY + maxHeight ) + { + maxHeight = nY + nH - topY; + } + } + + // prepare drawing mode + CGPathDrawingMode eMode; + if( IsBrushVisible() && IsPenVisible() ) + { + eMode = kCGPathEOFillStroke; + } + else if( IsPenVisible() ) + { + eMode = kCGPathStroke; + } + else if( IsBrushVisible() ) + { + eMode = kCGPathEOFill; + } + else + { + return; + } + // convert to CGPath + CGContextBeginPath( mrContext ); + if( IsPenVisible() ) + { + for( sal_uLong nPoly = 0; nPoly < nPolyCount; nPoly++ ) + { + const sal_uLong nPoints = pPoints[nPoly]; + if( nPoints > 1 ) + { + const SalPoint *pPtAry = ppPtAry[nPoly]; + float fX, fY; + alignLinePoint( pPtAry, fX, fY ); + CGContextMoveToPoint( mrContext, fX, fY ); + pPtAry++; + for( sal_uLong nPoint = 1; nPoint < nPoints; nPoint++, pPtAry++ ) + { + alignLinePoint( pPtAry, fX, fY ); + CGContextAddLineToPoint( mrContext, fX, fY ); + } + CGContextClosePath(mrContext); + } + } + } + else + { + for( sal_uLong nPoly = 0; nPoly < nPolyCount; nPoly++ ) + { + const sal_uLong nPoints = pPoints[nPoly]; + if( nPoints > 1 ) + { + const SalPoint *pPtAry = ppPtAry[nPoly]; + CGContextMoveToPoint( mrContext, pPtAry->mnX, pPtAry->mnY ); + pPtAry++; + for( sal_uLong nPoint = 1; nPoint < nPoints; nPoint++, pPtAry++ ) + { + CGContextAddLineToPoint( mrContext, pPtAry->mnX, pPtAry->mnY ); + } + CGContextClosePath(mrContext); + } + } + } + + CGContextDrawPath( mrContext, eMode ); + + RefreshRect( leftX, topY, maxWidth, maxHeight ); +} + +void IosSalGraphics::drawPolygon( sal_uLong nPoints, const SalPoint *pPtAry ) +{ + if( nPoints <= 1 ) + return; + if( !CheckContext() ) + return; + + long nX = 0, nY = 0, nWidth = 0, nHeight = 0; + getBoundRect( nPoints, pPtAry, nX, nY, nWidth, nHeight ); + + CGPathDrawingMode eMode; + if( IsBrushVisible() && IsPenVisible() ) + { + eMode = kCGPathEOFillStroke; + } + else if( IsPenVisible() ) + { + eMode = kCGPathStroke; + } + else if( IsBrushVisible() ) + { + eMode = kCGPathEOFill; + } + else + { + return; + } + CGContextBeginPath( mrContext ); + + if( IsPenVisible() ) + { + float fX, fY; + alignLinePoint( pPtAry, fX, fY ); + CGContextMoveToPoint( mrContext, fX, fY ); + pPtAry++; + for( sal_uLong nPoint = 1; nPoint < nPoints; nPoint++, pPtAry++ ) + { + alignLinePoint( pPtAry, fX, fY ); + CGContextAddLineToPoint( mrContext, fX, fY ); + } + } + else + { + CGContextMoveToPoint( mrContext, pPtAry->mnX, pPtAry->mnY ); + pPtAry++; + for( sal_uLong nPoint = 1; nPoint < nPoints; nPoint++, pPtAry++ ) + { + CGContextAddLineToPoint( mrContext, pPtAry->mnX, pPtAry->mnY ); + } + } + + CGContextDrawPath( mrContext, eMode ); + RefreshRect( nX, nY, nWidth, nHeight ); +} + +sal_Bool IosSalGraphics::drawPolygonBezier( sal_uLong, const SalPoint*, const sal_uInt8* ) +{ + return sal_False; +} + +sal_Bool IosSalGraphics::drawPolyPolygonBezier( sal_uLong, const sal_uLong*, + const SalPoint* const*, const sal_uInt8* const* ) +{ + return sal_False; +} + +void IosSalGraphics::drawRect( long nX, long nY, long nWidth, long nHeight ) +{ + if( !CheckContext() ) + { + return; + } + CGRect aRect( CGRectMake(nX, nY, nWidth, nHeight) ); + if( IsPenVisible() ) + { + aRect.origin.x += 0.5; + aRect.origin.y += 0.5; + aRect.size.width -= 1; + aRect.size.height -= 1; + } + + if( IsBrushVisible() ) + { + CGContextFillRect( mrContext, aRect ); + } + if( IsPenVisible() ) + { + CGContextStrokeRect( mrContext, aRect ); + } + RefreshRect( nX, nY, nWidth, nHeight ); +} + + +void IosSalGraphics::drawPolyLine( sal_uLong nPoints, const SalPoint *pPtAry ) +{ + if( nPoints < 1 ) + { + return; + } + if( !CheckContext() ) + { + return; + } + + long nX = 0, nY = 0, nWidth = 0, nHeight = 0; + getBoundRect( nPoints, pPtAry, nX, nY, nWidth, nHeight ); + + float fX, fY; + CGContextBeginPath( mrContext ); + alignLinePoint( pPtAry, fX, fY ); + CGContextMoveToPoint( mrContext, fX, fY ); + pPtAry++; + for( sal_uLong nPoint = 1; nPoint < nPoints; nPoint++, pPtAry++ ) + { + alignLinePoint( pPtAry, fX, fY ); + CGContextAddLineToPoint( mrContext, fX, fY ); + } + CGContextDrawPath( mrContext, kCGPathStroke ); + + RefreshRect( nX, nY, nWidth, nHeight ); +} + +sal_uInt16 IosSalGraphics::GetBitCount() const +{ + sal_uInt16 nBits = mnBitmapDepth ? mnBitmapDepth : 32;//24; + return nBits; +} + +SalBitmap* IosSalGraphics::getBitmap( long nX, long nY, long nDX, long nDY ) +{ + DBG_ASSERT( mxLayer, "IosSalGraphics::getBitmap() with no layer" ); + + ApplyXorContext(); + + IosSalBitmap* pBitmap = new IosSalBitmap; + if( !pBitmap->Create( mxLayer, mnBitmapDepth, nX, nY, nDX, nDY, !mbWindow ) ) + { + delete pBitmap; + pBitmap = NULL; + } + + return pBitmap; +} + +SystemGraphicsData IosSalGraphics::GetGraphicsData() const +{ + SystemGraphicsData aRes; + aRes.nSize = sizeof(aRes); + aRes.rCGContext = mrContext; + return aRes; +} + +long IosSalGraphics::GetGraphicsWidth() const +{ + long w = 0; + if( mrContext && (mbWindow || mbVirDev) ) + { + w = mnWidth; + } + + if( w == 0 ) + { + if( mbWindow && mpFrame ) + { + w = mpFrame->maGeometry.nWidth; + } + } + return w; +} + +SalColor IosSalGraphics::getPixel( long nX, long nY ) +{ + // return default value on printers or when out of bounds + if( !mxLayer || (nX < 0) || (nX >= mnWidth) || + (nY < 0) || (nY >= mnHeight)) + { + return COL_BLACK; + } + // prepare creation of matching a CGBitmapContext + CGColorSpaceRef aCGColorSpace = GetSalData()->mxRGBSpace; + CGBitmapInfo aCGBmpInfo = kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Big; +#if __BIG_ENDIAN__ + struct{ unsigned char b, g, r, a; } aPixel; +#else + struct{ unsigned char a, r, g, b; } aPixel; +#endif + + // create a one-pixel bitmap context + // TODO: is it worth to cache it? + CGContextRef xOnePixelContext = + ::CGBitmapContextCreate( &aPixel, 1, 1, 8, sizeof(aPixel), + aCGColorSpace, aCGBmpInfo ); + + // update this graphics layer + ApplyXorContext(); + + // copy the requested pixel into the bitmap context + if( IsFlipped() ) + { + nY = mnHeight - nY; + } + const CGPoint aCGPoint = {-nX, -nY}; + CGContextDrawLayerAtPoint( xOnePixelContext, aCGPoint, mxLayer ); + CGContextRelease( xOnePixelContext ); + + SalColor nSalColor = MAKE_SALCOLOR( aPixel.r, aPixel.g, aPixel.b ); + return nSalColor; +} + +void IosSalGraphics::GetResolution( long& rDPIX, long& rDPIY ) +{ + if( !mnRealDPIY ) + { + initResolution( (mbWindow && mpFrame) ? mpFrame->mpWindow : nil ); + } + + rDPIX = static_cast<long>(mfFakeDPIScale * mnRealDPIX); + rDPIY = static_cast<long>(mfFakeDPIScale * mnRealDPIY); +} + +void IosSalGraphics::ImplDrawPixel( long nX, long nY, const RGBAColor& rColor ) +{ + if( !CheckContext() ) + { + return; + } + // overwrite the fill color + CGContextSetFillColor( mrContext, rColor.AsArray() ); + // draw 1x1 rect, there is no pixel drawing in Quartz + CGRect aDstRect = {{nX,nY,},{1,1}}; + CGContextFillRect( mrContext, aDstRect ); + RefreshRect( aDstRect ); + // reset the fill color + CGContextSetFillColor( mrContext, maFillColor.AsArray() ); +} + +void IosSalGraphics::initResolution( UIWindow* ) +{ + // #i100617# read DPI only once; there is some kind of weird caching going on + // if the main screen changes + // FIXME: this is really unfortunate and needs to be investigated + + SalData* pSalData = GetSalData(); + if( pSalData->mnDPIX == 0 || pSalData->mnDPIY == 0 ) + { + UIScreen* pScreen = [UIScreen mainScreen]; + + mnRealDPIX = mnRealDPIY = 160; + if( pScreen ) + { + mnRealDPIX *= [pScreen scale]; + mnRealDPIY *= [pScreen scale]; + } + else + { + OSL_FAIL( "no screen found" ); + } + + pSalData->mnDPIX = mnRealDPIX; + pSalData->mnDPIY = mnRealDPIY; + } + else + { + mnRealDPIX = pSalData->mnDPIX; + mnRealDPIY = pSalData->mnDPIY; + } + + mfFakeDPIScale = 1.0; +} + +void IosSalGraphics::invert( long nX, long nY, long nWidth, long nHeight, SalInvert nFlags ) +{ + if ( CheckContext() ) + { + CGRect aCGRect = CGRectMake( nX, nY, nWidth, nHeight); + CGContextSaveGState(mrContext); + + if ( nFlags & SAL_INVERT_TRACKFRAME ) + { + const float dashLengths[2] = { 4.0, 4.0 }; // for drawing dashed line + CGContextSetBlendMode( mrContext, kCGBlendModeDifference ); + CGContextSetRGBStrokeColor ( mrContext, 1.0, 1.0, 1.0, 1.0 ); + CGContextSetLineDash ( mrContext, 0, dashLengths, 2 ); + CGContextSetLineWidth( mrContext, 2.0); + CGContextStrokeRect ( mrContext, aCGRect ); + } + else if ( nFlags & SAL_INVERT_50 ) + { + //CGContextSetAllowsAntialiasing( mrContext, false ); + CGContextSetBlendMode(mrContext, kCGBlendModeDifference); + CGContextAddRect( mrContext, aCGRect ); + Pattern50Fill(); + } + else // just invert + { + CGContextSetBlendMode(mrContext, kCGBlendModeDifference); + CGContextSetRGBFillColor ( mrContext,1.0, 1.0, 1.0 , 1.0 ); + CGContextFillRect ( mrContext, aCGRect ); + } + CGContextRestoreGState( mrContext); + RefreshRect( aCGRect ); + } +} + +void IosSalGraphics::invert( sal_uLong nPoints, const SalPoint* pPtAry, SalInvert nSalFlags ) +{ + CGPoint* CGpoints ; + if ( CheckContext() ) + { + CGContextSaveGState(mrContext); + CGpoints = makeCGptArray(nPoints,pPtAry); + CGContextAddLines ( mrContext, CGpoints, nPoints ); + if ( nSalFlags & SAL_INVERT_TRACKFRAME ) + { + const float dashLengths[2] = { 4.0, 4.0 }; // for drawing dashed line + CGContextSetBlendMode( mrContext, kCGBlendModeDifference ); + CGContextSetRGBStrokeColor ( mrContext, 1.0, 1.0, 1.0, 1.0 ); + CGContextSetLineDash ( mrContext, 0, dashLengths, 2 ); + CGContextSetLineWidth( mrContext, 2.0); + CGContextStrokePath ( mrContext ); + } + else if ( nSalFlags & SAL_INVERT_50 ) + { + CGContextSetBlendMode(mrContext, kCGBlendModeDifference); + Pattern50Fill(); + } + else // just invert + { + CGContextSetBlendMode( mrContext, kCGBlendModeDifference ); + CGContextSetRGBFillColor( mrContext, 1.0, 1.0, 1.0, 1.0 ); + CGContextFillPath( mrContext ); + } + const CGRect aRefreshRect = CGContextGetClipBoundingBox(mrContext); + CGContextRestoreGState( mrContext); + delete [] CGpoints; + RefreshRect( aRefreshRect ); + } +} + +void IosSalGraphics::Pattern50Fill() +{ + static const float aFillCol[4] = { 1,1,1,1 }; + static const CGPatternCallbacks aCallback = { 0, &DrawPattern50, NULL }; + if( ! GetSalData()->mxP50Space ) + { + GetSalData()->mxP50Space = CGColorSpaceCreatePattern( GetSalData()->mxRGBSpace ); + } + if( ! GetSalData()->mxP50Pattern ) + { + GetSalData()->mxP50Pattern = CGPatternCreate( NULL, CGRectMake( 0, 0, 4, 4 ), + CGAffineTransformIdentity, 4, 4, + kCGPatternTilingConstantSpacing, + false, &aCallback ); + } + CGContextSetFillColorSpace( mrContext, GetSalData()->mxP50Space ); + CGContextSetFillPattern( mrContext, GetSalData()->mxP50Pattern, aFillCol ); + CGContextFillPath( mrContext ); +} + + +void IosSalGraphics::ResetClipRegion() +{ + // release old path and indicate no clipping + if( mxClipPath ) + { + CGPathRelease( mxClipPath ); + mxClipPath = NULL; + } + if( CheckContext() ) + { + SetState(); + } +} + +void IosSalGraphics::SetLineColor() +{ + maLineColor.SetAlpha( 0.0 ); // transparent + if( CheckContext() ) + { + CGContextSetStrokeColor( mrContext, maLineColor.AsArray() ); + } +} + +void IosSalGraphics::SetLineColor( SalColor nSalColor ) +{ + maLineColor = RGBAColor( nSalColor ); + if( CheckContext() ) + { + CGContextSetStrokeColor( mrContext, maLineColor.AsArray() ); + } +} + +void IosSalGraphics::SetFillColor() +{ + maFillColor.SetAlpha( 0.0 ); // transparent + if( CheckContext() ) + { + CGContextSetFillColor( mrContext, maFillColor.AsArray() ); + } +} + +void IosSalGraphics::SetFillColor( SalColor nSalColor ) +{ + maFillColor = RGBAColor( nSalColor ); + if( CheckContext() ) + { + CGContextSetFillColor( mrContext, maFillColor.AsArray() ); + } +} + +bool IosSalGraphics::supportsOperation( OutDevSupportType eType ) const +{ + bool bRet = false; + switch( eType ) + { + case OutDevSupport_TransparentRect: + case OutDevSupport_B2DClip: + case OutDevSupport_B2DDraw: + bRet = true; + break; + default: break; + } + return bRet; +} + +bool IosSalGraphics::setClipRegion( const Region& i_rClip ) +{ + // release old clip path + if( mxClipPath ) + { + CGPathRelease( mxClipPath ); + mxClipPath = NULL; + } + mxClipPath = CGPathCreateMutable(); + + // set current path, either as polypolgon or sequence of rectangles + if( i_rClip.HasPolyPolygon() ) + { + basegfx::B2DPolyPolygon aClip( const_cast<Region&>(i_rClip).ConvertToB2DPolyPolygon() ); + AddPolyPolygonToPath( mxClipPath, aClip, !getAntiAliasB2DDraw(), false ); + } + else + { + long nX, nY, nW, nH; + ImplRegionInfo aInfo; + bool bRegionRect = i_rClip.ImplGetFirstRect(aInfo, nX, nY, nW, nH ); + while( bRegionRect ) + { + if( nW && nH ) + { + CGRect aRect = {{nX,nY}, {nW,nH}}; + CGPathAddRect( mxClipPath, NULL, aRect ); + } + bRegionRect = i_rClip.ImplGetNextRect( aInfo, nX, nY, nW, nH ); + } + } + // set the current path as clip region + if( CheckContext() ) + { + SetState(); + } + return true; +} + +void IosSalGraphics::SetROPFillColor( SalROPColor nROPColor ) +{ + if( ! mbPrinter ) + SetFillColor( ImplGetROPSalColor( nROPColor ) ); +} + +void IosSalGraphics::SetROPLineColor( SalROPColor nROPColor ) +{ + if( ! mbPrinter ) + SetLineColor( ImplGetROPSalColor( nROPColor ) ); +} + +void IosSalGraphics::SetXORMode( bool bSet, bool bInvertOnly ) +{ + // return early if XOR mode remains unchanged + if( mbPrinter ) + { + return; + } + if( ! bSet && mnXorMode == 2 ) + { + CGContextSetBlendMode( mrContext, kCGBlendModeNormal ); + mnXorMode = 0; + return; + } + else if( bSet && bInvertOnly && mnXorMode == 0) + { + CGContextSetBlendMode( mrContext, kCGBlendModeDifference ); + mnXorMode = 2; + return; + } + + if( (mpXorEmulation == NULL) && !bSet ) + { + return; + } + if( (mpXorEmulation != NULL) && (bSet == mpXorEmulation->IsEnabled()) ) + { + return; + } + if( !CheckContext() ) + { + return; + } + // prepare XOR emulation + if( !mpXorEmulation ) + { + mpXorEmulation = new XorEmulation(); + mpXorEmulation->SetTarget( mnWidth, mnHeight, mnBitmapDepth, mrContext, mxLayer ); + } + + // change the XOR mode + if( bSet ) + { + mpXorEmulation->Enable(); + mrContext = mpXorEmulation->GetMaskContext(); + mnXorMode = 1; + } + else + { + mpXorEmulation->UpdateTarget(); + mpXorEmulation->Disable(); + mrContext = mpXorEmulation->GetTargetContext(); + mnXorMode = 0; + } +} + +void IosSalGraphics::updateResolution() +{ + DBG_ASSERT( mbWindow, "updateResolution on inappropriate graphics" ); + + initResolution( (mbWindow && mpFrame) ? mpFrame->mpWindow : nil ); +} + + +// ----------------------------------------------------------- + +XorEmulation::XorEmulation() +: m_xTargetLayer( NULL ) +, m_xTargetContext( NULL ) +, m_xMaskContext( NULL ) +, m_xTempContext( NULL ) +, m_pMaskBuffer( NULL ) +, m_pTempBuffer( NULL ) +, m_nBufferLongs( 0 ) +, m_bIsEnabled( false ) +{} + +XorEmulation::~XorEmulation() +{ + Disable(); + SetTarget( 0, 0, 0, NULL, NULL ); +} + +void XorEmulation::SetTarget( int nWidth, int nHeight, int nTargetDepth, + CGContextRef xTargetContext, CGLayerRef xTargetLayer ) +{ + // prepare to replace old mask+temp context + if( m_xMaskContext ) + { + // cleanup the mask context + CGContextRelease( m_xMaskContext ); + delete[] m_pMaskBuffer; + m_xMaskContext = NULL; + m_pMaskBuffer = NULL; + + // cleanup the temp context if needed + if( m_xTempContext ) + { + CGContextRelease( m_xTempContext ); + delete[] m_pTempBuffer; + m_xTempContext = NULL; + m_pTempBuffer = NULL; + } + } + + // return early if there is nothing more to do + if( !xTargetContext ) + { + return; + } + // retarget drawing operations to the XOR mask + m_xTargetLayer = xTargetLayer; + m_xTargetContext = xTargetContext; + + // prepare creation of matching CGBitmaps + CGColorSpaceRef aCGColorSpace = GetSalData()->mxRGBSpace; + CGBitmapInfo aCGBmpInfo = kCGImageAlphaNoneSkipFirst; + int nBitDepth = nTargetDepth; + if( !nBitDepth ) + { + nBitDepth = 32; + } + int nBytesPerRow = (nBitDepth == 16) ? 2 : 4; + const size_t nBitsPerComponent = (nBitDepth == 16) ? 5 : 8; + if( nBitDepth <= 8 ) + { + aCGColorSpace = GetSalData()->mxGraySpace; + aCGBmpInfo = kCGImageAlphaNone; + nBytesPerRow = 1; + } + nBytesPerRow *= nWidth; + m_nBufferLongs = (nHeight * nBytesPerRow + sizeof(sal_uLong)-1) / sizeof(sal_uLong); + + // create a XorMask context + m_pMaskBuffer = new sal_uLong[ m_nBufferLongs ]; + m_xMaskContext = ::CGBitmapContextCreate( m_pMaskBuffer, + nWidth, nHeight, + nBitsPerComponent, nBytesPerRow, + aCGColorSpace, aCGBmpInfo ); + // reset the XOR mask to black + memset( m_pMaskBuffer, 0, m_nBufferLongs * sizeof(sal_uLong) ); + + // a bitmap context will be needed for manual XORing + // create one unless the target context is a bitmap context + if( nTargetDepth ) + m_pTempBuffer = (sal_uLong*)CGBitmapContextGetData( m_xTargetContext ); + if( !m_pTempBuffer ) + { + // create a bitmap context matching to the target context + m_pTempBuffer = new sal_uLong[ m_nBufferLongs ]; + m_xTempContext = ::CGBitmapContextCreate( m_pTempBuffer, + nWidth, nHeight, + nBitsPerComponent, nBytesPerRow, + aCGColorSpace, aCGBmpInfo ); + } + + // initialize XOR mask context for drawing + CGContextSetFillColorSpace( m_xMaskContext, aCGColorSpace ); + CGContextSetStrokeColorSpace( m_xMaskContext, aCGColorSpace ); + CGContextSetShouldAntialias( m_xMaskContext, false ); + + // improve the XorMask's XOR emulation a litte + // NOTE: currently only enabled for monochrome contexts + if( aCGColorSpace == GetSalData()->mxGraySpace ) + { + CGContextSetBlendMode( m_xMaskContext, kCGBlendModeDifference ); + } + // intialize the transformation matrix to the drawing target + const CGAffineTransform aCTM = CGContextGetCTM( xTargetContext ); + CGContextConcatCTM( m_xMaskContext, aCTM ); + if( m_xTempContext ) + { + CGContextConcatCTM( m_xTempContext, aCTM ); + } + // initialize the default XorMask graphics state + CGContextSaveGState( m_xMaskContext ); +} + +bool XorEmulation::UpdateTarget() +{ + if( !IsEnabled() ) + { + return false; + } + // update the temp bitmap buffer if needed + if( m_xTempContext ) + { + CGContextDrawLayerAtPoint( m_xTempContext, CGPointZero, m_xTargetLayer ); + } + // do a manual XOR with the XorMask + // this approach suffices for simple color manipulations + // and also the complex-clipping-XOR-trick used in metafiles + const sal_uLong* pSrc = m_pMaskBuffer; + sal_uLong* pDst = m_pTempBuffer; + for( int i = m_nBufferLongs; --i >= 0;) + { + *(pDst++) ^= *(pSrc++); + } + // write back the XOR results to the target context + if( m_xTempContext ) + { + CGImageRef xXorImage = CGBitmapContextCreateImage( m_xTempContext ); + const int nWidth = (int)CGImageGetWidth( xXorImage ); + const int nHeight = (int)CGImageGetHeight( xXorImage ); + // TODO: update minimal changerect + const CGRect aFullRect = {{0,0},{nWidth,nHeight}}; + CGContextDrawImage( m_xTargetContext, aFullRect, xXorImage ); + CGImageRelease( xXorImage ); + } + + // reset the XorMask to black again + // TODO: not needed for last update + memset( m_pMaskBuffer, 0, m_nBufferLongs * sizeof(sal_uLong) ); + + // TODO: return FALSE if target was not changed + return true; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/ios/source/gdi/salgdiutils.cxx b/vcl/ios/source/gdi/salgdiutils.cxx index e496493f9260..a9a97c82008d 100644 --- a/vcl/ios/source/gdi/salgdiutils.cxx +++ b/vcl/ios/source/gdi/salgdiutils.cxx @@ -237,6 +237,14 @@ bool IosSalGraphics::CheckContext() return (mrContext != NULL); } +CGContextRef IosSalGraphics::GetContext() +{ + if(!mrContext) + { + CheckContext(); + } + return mrContext; +} void IosSalGraphics::RefreshRect(float lX, float lY, float lWidth, float lHeight) { |