summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--canvas/source/cairo/cairo_textlayout.cxx6
-rw-r--r--vcl/Library_vcl.mk2
-rw-r--r--vcl/inc/ios/common.h34
-rw-r--r--vcl/inc/ios/salcoretextfontutils.hxx53
-rw-r--r--vcl/inc/ios/salcoretextlayout.hxx90
-rw-r--r--vcl/inc/ios/salcoretextstyle.hxx42
-rw-r--r--vcl/inc/ios/salgdi.h392
-rw-r--r--vcl/inc/ios/salgdicommon.hxx84
-rw-r--r--vcl/inc/vcl/sysdata.hxx2
-rw-r--r--vcl/ios/source/gdi/salcoretextfontutils.cxx609
-rw-r--r--vcl/ios/source/gdi/salcoretextlayout.cxx632
-rw-r--r--vcl/ios/source/gdi/salcoretextstyle.cxx96
-rw-r--r--vcl/ios/source/gdi/salgdi.cxx2412
-rw-r--r--vcl/ios/source/gdi/salgdicommon.cxx1581
-rw-r--r--vcl/ios/source/gdi/salgdiutils.cxx8
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)
{