diff options
author | Khaled Hosny <khaledhosny@eglug.org> | 2016-11-25 14:00:07 +0200 |
---|---|---|
committer | Khaled Hosny <khaledhosny@eglug.org> | 2016-11-26 14:28:39 +0000 |
commit | d761d952f460e1943e94c5a7556b3b01d2259666 (patch) | |
tree | cde2940e406e8451aa8acc8cd8d4305caaf6b626 /vcl/quartz | |
parent | 30ebc895c95ee66adf172717249aa1789b309eff (diff) |
Kill old Core Text layout engine
Change-Id: If80d65899255d8be72f374fbec232d103a08a006
Reviewed-on: https://gerrit.libreoffice.org/31232
Tested-by: Jenkins <ci@libreoffice.org>
Reviewed-by: Khaled Hosny <khaledhosny@eglug.org>
Diffstat (limited to 'vcl/quartz')
-rw-r--r-- | vcl/quartz/CTRunData.cxx | 94 | ||||
-rw-r--r-- | vcl/quartz/CTRunData.hxx | 42 | ||||
-rw-r--r-- | vcl/quartz/ctfonts.cxx | 17 | ||||
-rw-r--r-- | vcl/quartz/ctlayout.cxx | 787 | ||||
-rw-r--r-- | vcl/quartz/salgdi.cxx | 18 |
5 files changed, 7 insertions, 951 deletions
diff --git a/vcl/quartz/CTRunData.cxx b/vcl/quartz/CTRunData.cxx deleted file mode 100644 index 8f58d478646d..000000000000 --- a/vcl/quartz/CTRunData.cxx +++ /dev/null @@ -1,94 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * This file is part of the LibreOffice project. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - */ - -#include <sal/config.h> -#include <sal/types.h> - -#include <cassert> - -#include "CTRunData.hxx" -#include "quartz/utils.h" - - -CTRunData::CTRunData( CTRunRef pRun, int start) - : ownership_flags(0) - , m_StartPos(start) - , m_pRun(pRun) -{ - assert(pRun); - - CFDictionaryRef pRunAttributes = CTRunGetAttributes( m_pRun ); - m_pFont = static_cast<CTFontRef>(CFDictionaryGetValue( pRunAttributes, kCTFontAttributeName )); - - m_nGlyphs = CTRunGetGlyphCount(m_pRun); - m_EndPos = m_StartPos + m_nGlyphs; - const CFRange aAll = CFRangeMake( 0, m_nGlyphs ); - - m_pAdvances = CTRunGetAdvancesPtr( pRun ); - if( !m_pAdvances ) - { - m_pAdvances = new CGSize[m_nGlyphs]; - ownership_flags |= CTRUNDATA_F_OWN_ADVANCES; - CTRunGetAdvances( pRun, aAll, const_cast<CGSize*>(m_pAdvances) ); - } - - m_pGlyphs = CTRunGetGlyphsPtr( m_pRun ); - if( !m_pGlyphs ) - { - m_pGlyphs = new CGGlyph[m_nGlyphs]; - ownership_flags |= CTRUNDATA_F_OWN_GLYPHS; - CTRunGetGlyphs( pRun, aAll, const_cast<CGGlyph*>(m_pGlyphs)); - } - - m_pStringIndices = CTRunGetStringIndicesPtr( pRun ); - if( !m_pStringIndices ) - { - m_pStringIndices = new CFIndex[m_nGlyphs]; - ownership_flags |= CTRUNDATA_F_OWN_INDICES; - CTRunGetStringIndices( pRun, aAll, const_cast<CFIndex*>(m_pStringIndices) ); - } - - m_pPositions = CTRunGetPositionsPtr( pRun ); - if( !m_pPositions ) - { - m_pPositions = new CGPoint[m_nGlyphs]; - ownership_flags |= CTRUNDATA_F_OWN_POSITIONS; - CTRunGetPositions( pRun, aAll, const_cast<CGPoint*>(m_pPositions) ); - } - for(int i = 0; i < m_nGlyphs; i++) - { - SAL_INFO( "vcl.ct", "CTRunData Adv:" << (double)m_pAdvances[i].width << " s-idx:" << m_pStringIndices[i] << " pos:(" << - m_pPositions[i].x << ":" << m_pPositions[i].y << ")"); - } -} - -CTRunData::~CTRunData() -{ - if(ownership_flags & CTRUNDATA_F_OWN_ADVANCES) - { - delete [] m_pAdvances; - } - - if(ownership_flags & CTRUNDATA_F_OWN_GLYPHS) - { - delete [] m_pGlyphs; - } - - if(ownership_flags & CTRUNDATA_F_OWN_INDICES) - { - delete [] m_pStringIndices; - } - - if(ownership_flags & CTRUNDATA_F_OWN_POSITIONS) - { - delete [] m_pPositions; - } -} - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/quartz/CTRunData.hxx b/vcl/quartz/CTRunData.hxx deleted file mode 100644 index 3201acf08373..000000000000 --- a/vcl/quartz/CTRunData.hxx +++ /dev/null @@ -1,42 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * This file is part of the LibreOffice project. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - */ -#ifndef CTRunData_Included -#define CTRunData_Included - -#include "premac.h" -#include <CoreGraphics/CoreGraphics.h> -#include <CoreText/CoreText.h> -#include "postmac.h" - -class CTRunData -{ -public: - int ownership_flags; -#define CTRUNDATA_F_OWN_ADVANCES (1<<0) -#define CTRUNDATA_F_OWN_GLYPHS (1<<1) -#define CTRUNDATA_F_OWN_INDICES (1<<2) -#define CTRUNDATA_F_OWN_POSITIONS (1<<3) - - int m_nGlyphs; - int m_StartPos; - int m_EndPos; - CTRunRef m_pRun; - CTFontRef m_pFont; - const CGGlyph* m_pGlyphs; - const CGPoint* m_pPositions; - const CGSize* m_pAdvances; - const CFIndex* m_pStringIndices; - - CTRunData(CTRunRef pRun, int start); - ~CTRunData(); -}; - -#endif /* NDef CTRunData_Included */ - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/quartz/ctfonts.cxx b/vcl/quartz/ctfonts.cxx index 20f5414b2508..d5f29b5c073d 100644 --- a/vcl/quartz/ctfonts.cxx +++ b/vcl/quartz/ctfonts.cxx @@ -100,17 +100,6 @@ CoreTextStyle::CoreTextStyle( const FontSelectPattern& rFSD ) CTFontRef pNewCTFont = CTFontCreateWithFontDescriptor( pFontDesc, fScaledFontHeight, &aMatrix ); CFDictionarySetValue( mpStyleDict, kCTFontAttributeName, pNewCTFont ); CFRelease( pNewCTFont); - - // allow delayed setting the font color, i.e. after the text layout - CFDictionarySetValue( mpStyleDict, kCTForegroundColorFromContextAttributeName, kCFBooleanTrue ); - -#if 0 // LastResort is implicit in CoreText's font cascading - const void* aGFBDescriptors[] = { CTFontDescriptorCreateWithNameAndSize( CFSTR("LastResort"), 0) }; // TODO: use the full GFB list - const int nGfbCount = sizeof(aGFBDescriptors) / sizeof(*aGFBDescriptors); - CFArrayRef pGfbList = CFArrayCreate( NULL, aGFBDescriptors, nGfbCount, &kCFTypeArrayCallBacks); - CFDictionaryAddValue( mpStyleDict, kCTFontCascadeListAttribute, pGfbList); - CFRelease( pGfbList); -#endif } CoreTextStyle::~CoreTextStyle() @@ -171,7 +160,6 @@ SAL_WNODEPRECATED_DECLARATIONS_POP bool CoreTextStyle::GetGlyphBoundRect( sal_GlyphId aGlyphId, Rectangle& rRect ) const { CGGlyph nCGGlyph = aGlyphId & GF_IDXMASK; - // XXX: this is broken if the glyph came from fallback font CTFontRef aCTFontRef = static_cast<CTFontRef>(CFDictionaryGetValue( mpStyleDict, kCTFontAttributeName )); SAL_WNODEPRECATED_DECLARATIONS_PUSH //TODO: 10.11 kCTFontDefaultOrientation @@ -247,7 +235,6 @@ bool CoreTextStyle::GetGlyphOutline( sal_GlyphId aGlyphId, basegfx::B2DPolyPolyg rResult.clear(); CGGlyph nCGGlyph = aGlyphId & GF_IDXMASK; - // XXX: this is broken if the glyph came from fallback font CTFontRef pCTFont = static_cast<CTFontRef>(CFDictionaryGetValue( mpStyleDict, kCTFontAttributeName )); CGPathRef xPath = CTFontCreatePathForGlyph( pCTFont, nCGGlyph, nullptr ); if (!xPath) @@ -368,9 +355,9 @@ FontAttributes DevFontFromCTFontDescriptor( CTFontDescriptorRef pFD, bool* bFont // get font attributes CFDictionaryRef pAttrDict = static_cast<CFDictionaryRef>(CTFontDescriptorCopyAttribute( pFD, kCTFontTraitsAttribute )); - if (bFontEnabled && *bFontEnabled && SalLayout::UseCommonLayout()) + if (bFontEnabled && *bFontEnabled) { - // Ignore font formats not supported by CommonSalLayout. + // Ignore font formats not supported. int nFormat; CFNumberRef pFormat = static_cast<CFNumberRef>(CTFontDescriptorCopyAttribute(pFD, kCTFontFormatAttribute)); CFNumberGetValue(pFormat, kCFNumberIntType, &nFormat); diff --git a/vcl/quartz/ctlayout.cxx b/vcl/quartz/ctlayout.cxx deleted file mode 100644 index fcf474edd617..000000000000 --- a/vcl/quartz/ctlayout.cxx +++ /dev/null @@ -1,787 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * This file is part of the LibreOffice project. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * This file incorporates work covered by the following license notice: - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed - * with this work for additional information regarding copyright - * ownership. The ASF licenses this file to you under the Apache - * License, Version 2.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.apache.org/licenses/LICENSE-2.0 . - */ - -#include <sal/config.h> - -#include <memory> -#include <vector> - -#include <sal/types.h> -#include <tools/debug.hxx> - -#include "quartz/ctfonts.hxx" -#include "CTRunData.hxx" -#include "quartz/utils.h" - - -class CTLayout : public SalLayout -{ -public: - explicit CTLayout( const CoreTextStyle* ); - virtual ~CTLayout() override; - - virtual bool LayoutText( ImplLayoutArgs& ) override; - virtual void AdjustLayout( ImplLayoutArgs& ) override; - virtual void DrawText( SalGraphics& ) const override; - virtual bool DrawTextSpecial( SalGraphics& rGraphics, sal_uInt32 flags ) const override; - - virtual int GetNextGlyphs( int nLen, sal_GlyphId* pOutGlyphIds, Point& rPos, int&, - DeviceCoordinate* pGlyphAdvances = nullptr, int* pCharIndexes = nullptr, - const PhysicalFontFace** pFallbackFonts = nullptr ) const override; - - virtual DeviceCoordinate GetTextWidth() const override; - virtual DeviceCoordinate FillDXArray( DeviceCoordinate* pDXArray ) const override; - virtual sal_Int32 GetTextBreak(DeviceCoordinate nMaxWidth, DeviceCoordinate nCharExtra, int nFactor) const override; - virtual void GetCaretPositions( int nArraySize, long* pCaretXArray ) const override; - virtual bool GetBoundRect( SalGraphics&, Rectangle& ) const override; - - virtual void InitFont() const override; - virtual void MoveGlyph( int nStart, long nNewXPos ) override; - virtual void DropGlyph( int nStart ) override; - virtual void Simplify( bool bIsBase ) override; - -private: - void drawCTLine(AquaSalGraphics& rAquaGraphics, CTLineRef ctline, const CoreTextStyle* const pStyle) const; - CGPoint GetTextDrawPosition() const; - bool CacheGlyphLayout() const; - - const CoreTextStyle* const mpTextStyle; - - // CoreText specific objects - CFAttributedStringRef mpAttrString; - CTLineRef mpCTLine; - - int mnCharCount; // ==mnEndCharPos-mnMinCharPos - int mnTrailingSpaceCount; - double mfTrailingSpaceWidth; - - // cached details about the resulting layout - // mutable members since these details are all lazy initialized - mutable double mfCachedWidth; // cached value of resulting typographical width - - // x-offset relative to layout origin - // currently only used in RTL-layouts - mutable double mfBaseAdv; - - mutable bool bLayouted; // true if the glyph layout information are cached and current; - mutable std::vector<std::unique_ptr<CTRunData>> m_vRunData; - -}; - -CTLayout::CTLayout( const CoreTextStyle* pTextStyle ) - : mpTextStyle( pTextStyle ) - , mpAttrString( nullptr ) - , mpCTLine( nullptr ) - , mnCharCount( 0 ) - , mnTrailingSpaceCount( 0 ) - , mfTrailingSpaceWidth( 0.0 ) - , mfCachedWidth( -1 ) - , mfBaseAdv( 0 ) - , bLayouted( false ) -{ -} - -CTLayout::~CTLayout() -{ - if( mpCTLine ) - { - SAL_INFO( "vcl.ct", "CFRelease(" << mpCTLine << ")" ); - CFRelease( mpCTLine ); - } - if( mpAttrString ) - CFRelease( mpAttrString ); -} - -bool CTLayout::LayoutText( ImplLayoutArgs& rArgs ) -{ - m_vRunData.clear(); - bLayouted = false; - - // release an eventual older layout - if( mpAttrString ) - CFRelease( mpAttrString ); - mpAttrString = nullptr; - if( mpCTLine ) - { - SAL_INFO( "vcl.ct", "CFRelease(" << mpCTLine << ")" ); - CFRelease( mpCTLine ); - } - mpCTLine = nullptr; - - // initialize the new layout - SalLayout::AdjustLayout( rArgs ); - mnCharCount = mnEndCharPos - mnMinCharPos; - - // short circuit if there is nothing to do - if( mnCharCount <= 0 ) - return false; - - const sal_Unicode *pStr = rArgs.mrStr.getStr(); - - // create the CoreText line layout - CFStringRef aCFText = CFStringCreateWithCharactersNoCopy( nullptr, - reinterpret_cast<UniChar const *>(pStr + mnMinCharPos), - mnCharCount, - kCFAllocatorNull ); - // CFAttributedStringCreate copies the attribues parameter - mpAttrString = CFAttributedStringCreate( nullptr, aCFText, mpTextStyle->GetStyleDict() ); - mpCTLine = CTLineCreateWithAttributedString( mpAttrString ); - SAL_INFO( "vcl.ct", "CTLineCreateWithAttributedString(\"" << GetOUString(aCFText) << "\") =p " << mpCTLine ); - CFRelease( aCFText); - - mnTrailingSpaceCount = 0; - // reverse search for first 'non-space'... - for( int i = mnEndCharPos - 1; i >= mnMinCharPos; i--) - { - sal_Unicode nChar = pStr[i]; - if ((nChar <= 0x0020) || // blank - (nChar == 0x00A0) || // non breaking space - (nChar >= 0x2000 && nChar <= 0x200F) || // whitespace - (nChar == 0x3000)) // ideographic space - { - mnTrailingSpaceCount += 1; - } - else - { - break; - } - } - return true; -} - -void CTLayout::AdjustLayout( ImplLayoutArgs& rArgs ) -{ - if( !mpCTLine) - { - return; - } - - - int nPixelWidth = rArgs.mpDXArray ? rArgs.mpDXArray[ mnCharCount - 1 ] : rArgs.mnLayoutWidth; - if( nPixelWidth <= 0) - return; - - // HACK: justification requests which change the width by just one pixel are probably - // #i86038# introduced by lossy conversions between integer based coordinate system - int fuzz = (nPixelWidth - GetTextWidth()) / 2; - if (!fuzz) - { - return; - } - - // if the text to be justified has whitespace in it then - // - Writer goes crazy with its HalfSpace magic - // - CoreText handles spaces specially (in particular at the text end) - if( mnTrailingSpaceCount ) - { - if(rArgs.mpDXArray) - { - int nFullPixelWidth = nPixelWidth; - nPixelWidth = mnTrailingSpaceCount == mnCharCount - ? 0 : rArgs.mpDXArray[ mnCharCount - mnTrailingSpaceCount - 1]; - mfTrailingSpaceWidth = nFullPixelWidth - nPixelWidth; - } - else - { - if(mfTrailingSpaceWidth <= 0.0) - { - mfTrailingSpaceWidth = CTLineGetTrailingWhitespaceWidth( mpCTLine ); - nPixelWidth -= rint(mfTrailingSpaceWidth); - } - } - if(nPixelWidth <= 0) - { - return; - } - // recreate the CoreText line layout without trailing spaces - SAL_INFO( "vcl.ct", "CFRelease(" << mpCTLine << ")" ); - CFRelease( mpCTLine ); - const sal_Unicode *pStr = rArgs.mrStr.getStr(); - CFStringRef aCFText = CFStringCreateWithCharactersNoCopy( nullptr, - reinterpret_cast<UniChar const *>(pStr + mnMinCharPos), - mnCharCount - mnTrailingSpaceCount, - kCFAllocatorNull ); - CFAttributedStringRef pAttrStr = CFAttributedStringCreate( nullptr, - aCFText, - mpTextStyle->GetStyleDict() ); - mpCTLine = CTLineCreateWithAttributedString( pAttrStr ); - SAL_INFO( "vcl.ct", "CTLineCreateWithAttributedString(\"" << GetOUString(aCFText) << "\") = " << mpCTLine ); - CFRelease( pAttrStr ); - CFRelease( aCFText ); - - - // in RTL-layouts trailing spaces are leftmost - // TODO: use BiDi-algorithm to thoroughly check this assumption - if( rArgs.mnFlags & SalLayoutFlags::BiDiRtl) - { - mfBaseAdv = mfTrailingSpaceWidth; - } - } - - CTLineRef pNewCTLine = CTLineCreateJustifiedLine( mpCTLine, 1.0, nPixelWidth); - SAL_INFO( "vcl.ct", "CTLineCreateJustifiedLine(" << mpCTLine << ",1.0," << nPixelWidth << ") = " << pNewCTLine ); - - if( !pNewCTLine ) - { - // CTLineCreateJustifiedLine can and does fail - // handle failure by keeping the unjustified layout - // TODO: a better solution such as - // - forcing glyph overlap - // - changing the font size - // - changing the CTM matrix - return; - } - SAL_INFO( "vcl.ct", "CFRelease(" << mpCTLine << ")" ); - CFRelease( mpCTLine ); - mpCTLine = pNewCTLine; - mfCachedWidth = nPixelWidth + mfTrailingSpaceWidth; -} - -// When drawing right aligned text, rounding errors in the position returned by -// GetDrawPosition() cause the right margin of the text to change whenever text -// width changes causing "jumping letters" effect. So here we calculate the -// drawing position relative to the right margin on our own to avoid the -// rounding errors. That is basically a hack, and it should go away if one day -// we managed to get rid of those rounding errors. - -// We continue using GetDrawPosition() for non-right aligned text, to minimize -// any unforeseen side effects. -CGPoint CTLayout::GetTextDrawPosition() const -{ - CGFloat fPosX, fPosY; - - if (mnLayoutFlags & SalLayoutFlags::RightAlign) - { - // text is always drawn at its leftmost point - const Point aPos = DrawBase(); - fPosX = aPos.X() + mfBaseAdv - GetTextWidth(); - fPosY = aPos.Y(); - } - else - { - const Point aPos = GetDrawPosition(Point(mfBaseAdv, 0)); - fPosX = aPos.X(); - fPosY = aPos.Y(); - } - - CGPoint aTextPos = { +fPosX, -fPosY }; - return aTextPos; -} - -/* use to deal with special font decoration like 'outline' drawing - * return true if it was able to handle the drawing - * false if not, in which case the caller - * is supposed to fallback to 'generic' method - */ -bool CTLayout::DrawTextSpecial( SalGraphics& rGraphics, sal_uInt32 flags ) const -{ - AquaSalGraphics& rAquaGraphics = static_cast<AquaSalGraphics&>(rGraphics); - - // short circuit if there is nothing to do - if( (mnCharCount <= 0) || !rAquaGraphics.CheckContext() ) - return true; -#if 0 /* temporarely revert to the 'old way' */ - if (flags & DRAWTEXT_F_OUTLINE) - { - CFMutableDictionaryRef styledict = CFDictionaryCreateMutableCopy( - CFAllocatorGetDefault(), - CFDictionaryGetCount(mpTextStyle->GetStyleDict()), - mpTextStyle->GetStyleDict()); - - int nStroke = 2; - CFNumberRef rStroke = CFNumberCreate(NULL, kCFNumberSInt32Type, &nStroke); - CFDictionarySetValue(styledict, kCTStrokeWidthAttributeName, rStroke); - - CFAttributedStringRef pAttrStr = CFAttributedStringCreate( - NULL, - CFAttributedStringGetString(mpAttrString), - styledict); - CTLineRef pCTLine = CTLineCreateWithAttributedString( pAttrStr ); - SAL_INFO( "vcl.ct", "CTLineCreateWithAttributedString(" << GetOUString(CFAttributedStringGetString(mpAttrSring)) << ") = " << pCTLine ); - CFRelease( pAttrStr ); - - /* draw the text in 'outline' */ - drawCTLine(rAquaGraphics, pCTLine, mpTextStyle); - SAL_INFO( "vcl.ct", "CFRelease(" << pCTLine << ")" ); - CFRelease(pCTLine); - return true; - } - else -#endif - { - return SalLayout::DrawTextSpecial(rGraphics, flags); - } -} - -void CTLayout::drawCTLine(AquaSalGraphics& rAquaGraphics, CTLineRef ctline, const CoreTextStyle* const pStyle) const -{ - // the view is vertically flipped => flipped glyphs - // so apply a temporary transformation that it flips back - // also compensate if the font was size limited - CGContextRef context = rAquaGraphics.mrContext; - SAL_INFO( "vcl.ct", "CGContextSaveGState(" << context << ")" ); - CGContextSaveGState( context ); - SAL_INFO( "vcl.ct", "CGContextScaleCTM(" << context << ",1.0,-1.0)" ); - CGContextScaleCTM( context, 1.0, -1.0 ); - CGContextSetShouldAntialias( context, !rAquaGraphics.mbNonAntialiasedText ); - - // set the text transformation (e.g. position) - CGPoint aTextPos = GetTextDrawPosition(); - - if( pStyle->mfFontRotation != 0.0 ) - { - const CGFloat fRadians = pStyle->mfFontRotation; - SAL_INFO( "vcl.ct", "CGContextRotateCTM(" << context << "," << +fRadians << ")" ); - CGContextRotateCTM( context, +fRadians ); - - const CGAffineTransform aInvMatrix = CGAffineTransformMakeRotation( -fRadians ); - aTextPos = CGPointApplyAffineTransform( aTextPos, aInvMatrix ); - } - - SAL_INFO( "vcl.ct", "CGContextSetTextPosition(" << context << "," << aTextPos << ")" ); - CGContextSetTextPosition( context, aTextPos.x, aTextPos.y ); - -#ifndef IOS - // request an update of the to-be-changed window area - if( rAquaGraphics.IsWindowGraphics() ) - { - const CGRect aInkRect = CTLineGetImageBounds( mpCTLine, context ); - const CGRect aRefreshRect = CGContextConvertRectToDeviceSpace( context, aInkRect ); - rAquaGraphics.RefreshRect( aRefreshRect ); - } -#endif - - // set the text color as fill color (see kCTForegroundColorFromContextAttributeName) - CGContextSetFillColor( context, rAquaGraphics.maTextColor.AsArray() ); - - SAL_INFO( "vcl.ct", "CTLineDraw(" << ctline << "," << context << ")" ); - // draw the text - CTLineDraw( ctline, context ); - - if(mnLayoutFlags & SalLayoutFlags::DrawBullet) - { - CFArrayRef runArray = CTLineGetGlyphRuns(ctline); - CFIndex runCount = CFArrayGetCount(runArray); - - for (CFIndex runIndex = 0; runIndex < runCount; runIndex++) - { - CTRunRef run = static_cast<CTRunRef>(CFArrayGetValueAtIndex(runArray, runIndex)); - CFIndex runGlyphCount = CTRunGetGlyphCount(run); - CGPoint position; - CGSize advance; - CFIndex runGlyphIndex = 0; - CFIndex stringIndice = 0; - - for (; runGlyphIndex < runGlyphCount; runGlyphIndex++) - { - CFRange glyphRange = CFRangeMake(runGlyphIndex, 1); - CTRunGetStringIndices( run, glyphRange, &stringIndice ); - UniChar curChar = CFStringGetCharacterAtIndex (CFAttributedStringGetString(mpAttrString), stringIndice); - if(curChar == ' ') - { - CGFloat ascent; - CGFloat descent; - CGFloat leading; - CTFontRef runFont = static_cast<CTFontRef>(CFDictionaryGetValue(CTRunGetAttributes(run), - kCTFontAttributeName)); - CGFloat baseSize = CTFontGetSize(runFont); - CTRunGetTypographicBounds ( run, glyphRange, - &ascent, &descent, &leading); - CTRunGetPositions(run, glyphRange, &position); - CTRunGetAdvances(run, glyphRange, &advance); - CGRect bulletRect; - if(mnLayoutFlags & SalLayoutFlags::Vertical) - { - bulletRect = CGRectMake(position.x - advance.width / 4, - -position.y, baseSize / 5, baseSize / 5 ); - } - else - { - bulletRect = CGRectMake(position.x + advance.width / 4, - position.y + ascent / 3 - baseSize / 5, baseSize / 5, baseSize / 5 ); - } - - CGContextSaveGState(context); - CGContextTranslateCTM(context, aTextPos.x, aTextPos.y); - RGBAColor bulletColor(MAKE_SALCOLOR(0x26, 0x8b, 0xd2 )); // NON_PRINTING_CHARACTER_COLOR - CGContextSetFillColor( context, bulletColor.AsArray() ); - CGContextSetStrokeColor(context, bulletColor.AsArray()); - if(mnLayoutFlags & SalLayoutFlags::Vertical) - { - CGContextRotateCTM( context, -F_PI/2 ); - } - - CGContextBeginPath(context); - CGContextAddEllipseInRect(context, bulletRect); - CGContextDrawPath(context, kCGPathFillStroke); // Or kCGPathFill - CGContextRestoreGState(context); - } - } - } - } - // restore the original graphic context transformations - SAL_INFO( "vcl.ct", "CGContextRestoreGState(" << context << ")" ); - CGContextRestoreGState( context ); -} - -void CTLayout::DrawText( SalGraphics& rGraphics ) const -{ - AquaSalGraphics& rAquaGraphics = static_cast<AquaSalGraphics&>(rGraphics); - - // short circuit if there is nothing to do - if( (mnCharCount <= 0) || !rAquaGraphics.CheckContext() ) - return; - - drawCTLine(rAquaGraphics, mpCTLine, mpTextStyle); -} - -bool CTLayout::CacheGlyphLayout() const // eew! -{ - m_vRunData.clear(); - if(!mpCTLine) - { - return false; - } - CFArrayRef aRuns = CTLineGetGlyphRuns( mpCTLine ); - const int nRun = CFArrayGetCount( aRuns ); - int nPos = 0; - - for( int i = 0; i < nRun; ++i ) - { - CTRunRef pRun = static_cast<CTRunRef>(CFArrayGetValueAtIndex( aRuns, i )); - CTRunData* pRunData = new CTRunData(pRun, nPos); - m_vRunData.push_back(std::unique_ptr<CTRunData>(pRunData)); - nPos += pRunData->m_nGlyphs; - } - bLayouted = true; - return true; -} - -int CTLayout::GetNextGlyphs( int nLen, sal_GlyphId* pOutGlyphIds, Point& rPos, int& nStart, - DeviceCoordinate* pGlyphAdvances, int* pCharIndexes, - const PhysicalFontFace** pFallbackFonts ) const -{ - if( !mpCTLine ) - { - return 0; - } - if(!bLayouted) - { - CacheGlyphLayout(); - } - - if( nStart < 0 ) // first glyph requested? - { - nStart = 0; - } - const PhysicalFontFace* pFallbackFont = nullptr; - CTFontRef pFont = nullptr; - CTFontDescriptorRef pFontDesc = nullptr; - FontAttributes rDevFontAttr; - - auto iter = m_vRunData.begin(); - - while (iter != m_vRunData.end() && (*iter)->m_EndPos <= nStart) - { - ++iter; - } - if(iter == m_vRunData.end()) - { - return 0; - } - else - { - if( pFallbackFonts ) - { - pFont = static_cast<CTFontRef>(CFDictionaryGetValue( mpTextStyle->GetStyleDict(), kCTFontAttributeName )); - pFontDesc = CTFontCopyFontDescriptor( (*iter)->m_pFont ); - rDevFontAttr = DevFontFromCTFontDescriptor( pFontDesc, nullptr ); - } - } - int i = nStart; - int count = 0; - while( i < nStart + nLen ) - { - // convert glyph details for VCL - int j = i - (*iter)->m_StartPos; - *(pOutGlyphIds++) = (*iter)->m_pGlyphs[ j ]; - if( pGlyphAdvances ) - { - *(pGlyphAdvances++) = lrint((*iter)->m_pAdvances[ j ].width); - } - if( pCharIndexes ) - { - *(pCharIndexes++) = (*iter)->m_pStringIndices[ j ] + mnMinCharPos; - } - if( pFallbackFonts ) - { - if (!CFEqual((*iter)->m_pFont, pFont)) - { - pFallbackFont = new CoreTextFontFace( rDevFontAttr, reinterpret_cast<sal_IntPtr>(pFontDesc) ); - *(pFallbackFonts++) = pFallbackFont; - } - else - { - *(pFallbackFonts++) = nullptr; - } - } - if( i == nStart ) - { - const CGPoint& rFirstPos = (*iter)->m_pPositions[ j ]; - rPos = GetDrawPosition( Point( rFirstPos.x, rFirstPos.y) ); - } - i += 1; - count += 1; - if (i == (*iter)->m_EndPos) - { - // note: we assume that we do not have empty runs in the middle of things - ++iter; - if (iter == m_vRunData.end()) - { - break; - } - if( pFallbackFonts ) - { - pFont = static_cast<CTFontRef>(CFDictionaryGetValue( mpTextStyle->GetStyleDict(), kCTFontAttributeName )); - pFontDesc = CTFontCopyFontDescriptor( (*iter)->m_pFont ); - rDevFontAttr = DevFontFromCTFontDescriptor( pFontDesc, nullptr ); - } - } - } - nStart = i; - - return count; - -} - -DeviceCoordinate CTLayout::GetTextWidth() const -{ - if( (mnCharCount <= 0) || !mpCTLine ) - return 0; - - if( mfCachedWidth < 0.0 ) - { - mfCachedWidth = CTLineGetTypographicBounds( mpCTLine, nullptr, nullptr, nullptr); - } - - return mfCachedWidth; -} - -DeviceCoordinate CTLayout::FillDXArray( DeviceCoordinate* pDXArray ) const -{ - DeviceCoordinate nPixelWidth = GetTextWidth(); - - // short circuit requests which don't need full details - if( !pDXArray ) - { - return nPixelWidth; - } - - for(int i = 0; i < mnCharCount; i++) - { - pDXArray[i] = 0.0; - } - - // prepare the sub-pixel accurate logical-width array - ::std::vector<float> aWidthVector( mnCharCount ); - if( mnTrailingSpaceCount && (mfTrailingSpaceWidth > 0.0) ) - { - const double fOneWidth = mfTrailingSpaceWidth / mnTrailingSpaceCount; - for(int i = mnCharCount - mnTrailingSpaceCount; i < mnCharCount; i++) - { - aWidthVector[i] = fOneWidth; - } - } - - // handle each glyph run - CFArrayRef aGlyphRuns = CTLineGetGlyphRuns( mpCTLine ); - const int nRunCount = CFArrayGetCount( aGlyphRuns ); - typedef std::vector<CGSize> CGSizeVector; - CGSizeVector aSizeVector; - typedef std::vector<CFIndex> CFIndexVector; - CFIndexVector aIndexVector; - - for( int nRunIndex = 0; nRunIndex < nRunCount; ++nRunIndex ) - { - CTRunRef pGlyphRun = static_cast<CTRunRef>(CFArrayGetValueAtIndex( aGlyphRuns, nRunIndex )); - const CFIndex nGlyphCount = CTRunGetGlyphCount( pGlyphRun ); - const CFRange aFullRange = CFRangeMake( 0, nGlyphCount ); - - aSizeVector.resize( nGlyphCount ); - aIndexVector.resize( nGlyphCount ); - CTRunGetAdvances( pGlyphRun, aFullRange, &aSizeVector[0] ); - CTRunGetStringIndices( pGlyphRun, aFullRange, &aIndexVector[0] ); - - for( int i = 0; i != nGlyphCount; ++i ) - { - const int nRelIndex = aIndexVector[i]; - SAL_INFO( "vcl.ct", "aWidthVector[ g:" << i << "-> c:" << nRelIndex << " ] = " << - aWidthVector[nRelIndex] << " + " << aSizeVector[i].width << " = " << - aWidthVector[nRelIndex] + aSizeVector[i].width); - aWidthVector[nRelIndex] += aSizeVector[i].width; - } - } - - // convert the sub-pixel accurate array into classic pDXArray integers - float fWidthSum = 0.0; - sal_Int32 nOldDX = 0; - for( int i = 0; i < mnCharCount; ++i) - { - const sal_Int32 nNewDX = rint( fWidthSum += aWidthVector[i]); - pDXArray[i] = nNewDX - nOldDX; - nOldDX = nNewDX; - } - return nPixelWidth; -} - -sal_Int32 CTLayout::GetTextBreak( DeviceCoordinate nMaxWidth, DeviceCoordinate nCharExtra, int nFactor ) const -{ - if( !mpCTLine ) - { - SAL_INFO("vcl.ct", "GetTextBreak mpCTLine == NULL"); - return -1; - } - CTTypesetterRef aCTTypeSetter = CTTypesetterCreateWithAttributedString( mpAttrString ); - CFIndex nBestGuess = (nCharExtra >= 0) ? 0 : mnCharCount; - for( int i = 1; i <= mnCharCount; i *= 2 ) - { - // guess the target width considering char-extra expansion/condensation - const double nTargetWidth = nMaxWidth - nBestGuess * nCharExtra; - const double fCTMaxWidth = nTargetWidth / nFactor; - // calculate the breaking index for the guessed target width - const CFIndex nNewIndex = CTTypesetterSuggestClusterBreak( aCTTypeSetter, 0, fCTMaxWidth ); - if( nNewIndex >= mnCharCount ) - { - CFRelease( aCTTypeSetter ); - return -1; - } - // check if the original extra-width guess was good - if( !nCharExtra ) - nBestGuess = nNewIndex; - - if( nBestGuess == nNewIndex ) - break; - - // prepare another round for a different number of characters - CFIndex nNewGuess = (nNewIndex + nBestGuess + 1) / 2; - if( nNewGuess == nBestGuess ) - { - nNewGuess += (nNewIndex > nBestGuess) ? +1 : -1; - } - nBestGuess = nNewGuess; - } - - // suggest the best fitting cluster break as breaking position - CFRelease( aCTTypeSetter ); - - const int nIndex = nBestGuess + mnMinCharPos; - SAL_INFO("vcl.ct", "GetTextBreak nIndex:" << nIndex); - - return nIndex; -} - -void CTLayout::GetCaretPositions( int nMaxIndex, long* pCaretXArray ) const -{ - SAL_WARN_IF( (nMaxIndex<=0) || (nMaxIndex&1), "vcl", - "CTLayout::GetCaretPositions() : invalid number of caret pairs requested"); - - // initialize the caret positions - for( int i = 0; i < nMaxIndex; ++i ) - { - pCaretXArray[ i ] = -1; - } - for( int n = 0; n <= mnCharCount; ++n ) - { - // measure the characters cursor position - CGFloat fPos2 = -1; - const CGFloat fPos1 = CTLineGetOffsetForStringIndex( mpCTLine, n, &fPos2 ); - (void)fPos2; // TODO: split cursor at line direction change - - // update previous trailing position - if( n > 0 ) - pCaretXArray[ 2*n-1 ] = lrint( fPos1 ); - - // update current leading position - if( 2*n >= nMaxIndex ) - break; - pCaretXArray[ 2*n+0 ] = lrint( fPos1 ); - } -} - -bool CTLayout::GetBoundRect( SalGraphics& rGraphics, Rectangle& rVCLRect ) const -{ - // Closely mimic DrawText(), except that instead of calling - // CTLineDraw() to draw the line, we call CTLineGetImageBounds() - // to get its bounds. But all the coordinate system manipulation - // before that is the same => should be factored out? - - AquaSalGraphics& rAquaGraphics = static_cast<AquaSalGraphics&>(rGraphics); - - if( !rAquaGraphics.CheckContext() ) - return false; - - CGContextSaveGState( rAquaGraphics.mrContext ); - CGContextScaleCTM( rAquaGraphics.mrContext, 1.0, -1.0 ); - CGContextSetShouldAntialias( rAquaGraphics.mrContext, !rAquaGraphics.mbNonAntialiasedText ); - - const CGPoint aVclPos = GetTextDrawPosition(); - CGPoint aTextPos = GetTextDrawPosition(); - - if( mpTextStyle->mfFontRotation != 0.0 ) - { - const CGFloat fRadians = mpTextStyle->mfFontRotation; - CGContextRotateCTM( rAquaGraphics.mrContext, +fRadians ); - - const CGAffineTransform aInvMatrix = CGAffineTransformMakeRotation( -fRadians ); - aTextPos = CGPointApplyAffineTransform( aTextPos, aInvMatrix ); - } - - CGContextSetTextPosition( rAquaGraphics.mrContext, aTextPos.x, aTextPos.y ); - CGRect aMacRect = CTLineGetImageBounds( mpCTLine, rAquaGraphics.mrContext ); - - if( mpTextStyle->mfFontRotation != 0.0 ) - { - const CGFloat fRadians = mpTextStyle->mfFontRotation; - const CGAffineTransform aMatrix = CGAffineTransformMakeRotation( +fRadians ); - aMacRect = CGRectApplyAffineTransform( aMacRect, aMatrix ); - } - - CGContextRestoreGState( rAquaGraphics.mrContext ); - - rVCLRect.Left() = aVclPos.x + lrint(aMacRect.origin.x); - rVCLRect.Right() = aVclPos.x + lrint(aMacRect.origin.x + aMacRect.size.width); - rVCLRect.Bottom() = aVclPos.x - lrint(aMacRect.origin.y); - rVCLRect.Top() = aVclPos.x - lrint(aMacRect.origin.y + aMacRect.size.height); - - return true; -} - -// glyph fallback is supported directly by Aqua -// so methods used only by MultiSalLayout can be dummy implementated -void CTLayout::InitFont() const {} -void CTLayout::MoveGlyph( int /*nStart*/, long /*nNewXPos*/ ) {} -void CTLayout::DropGlyph( int /*nStart*/ ) {} -void CTLayout::Simplify( bool /*bIsBase*/ ) {} - -SalLayout* CoreTextStyle::GetTextLayout() const -{ - return new CTLayout( this); -} - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/quartz/salgdi.cxx b/vcl/quartz/salgdi.cxx index a58870f825af..0333bbf0f6c2 100644 --- a/vcl/quartz/salgdi.cxx +++ b/vcl/quartz/salgdi.cxx @@ -380,11 +380,8 @@ void AquaSalGraphics::GetDevFontList( PhysicalFontCollection* pFontCollection ) // Copy all PhysicalFontFace objects contained in the SystemFontList pSalData->mpFontList->AnnounceFonts( *pFontCollection ); - if (SalLayout::UseCommonLayout()) - { - static CoreTextGlyphFallbackSubstititution aSubstFallback; - pFontCollection->SetFallbackHook(&aSubstFallback); - } + static CoreTextGlyphFallbackSubstititution aSubstFallback; + pFontCollection->SetFallbackHook(&aSubstFallback); } void AquaSalGraphics::ClearDevFontCache() @@ -534,15 +531,10 @@ void AquaSalGraphics::SetFont(FontSelectPattern* pReqFont, int nFallbackLevel) SalLayout* AquaSalGraphics::GetTextLayout(ImplLayoutArgs& /*rArgs*/, int nFallbackLevel) { - SalLayout* pSalLayout = nullptr; if (mpTextStyle[nFallbackLevel]) - { - if (SalLayout::UseCommonLayout()) - pSalLayout = new CommonSalLayout(*mpTextStyle[nFallbackLevel]); - else - pSalLayout = mpTextStyle[nFallbackLevel]->GetTextLayout(); - } - return pSalLayout; + return new CommonSalLayout(*mpTextStyle[nFallbackLevel]); + + return nullptr; } const FontCharMapRef AquaSalGraphics::GetFontCharMap() const |