/* -*- 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include // The only common SalFrame method SalFrameGeometry SalFrame::GetGeometry() const { // mirror frame coordinates at parent SalFrame *pParent = GetParent(); if( pParent && AllSettings::GetLayoutRTL() ) { SalFrameGeometry aGeom = maGeometry; int parent_x = aGeom.nX - pParent->maGeometry.nX; aGeom.nX = pParent->maGeometry.nX + pParent->maGeometry.nWidth - maGeometry.nWidth - parent_x; return aGeom; } else return maGeometry; } SalGraphics::SalGraphics() : m_nLayout( SalLayoutFlags::NONE ), m_eLastMirrorMode(MirrorMode::NONE), m_nLastMirrorTranslation(0), m_bAntiAlias(false), m_bTextRenderModeForResolutionIndependentLayout(false) { // read global RTL settings if( AllSettings::GetLayoutRTL() ) m_nLayout = SalLayoutFlags::BiDiRtl; } bool SalGraphics::initWidgetDrawBackends(bool bForce) { bool bFileDefinitionsWidgetDraw = !!getenv("VCL_DRAW_WIDGETS_FROM_FILE"); if (bFileDefinitionsWidgetDraw || bForce) { m_pWidgetDraw.reset(new vcl::FileDefinitionWidgetDraw(*this)); auto pFileDefinitionWidgetDraw = static_cast(m_pWidgetDraw.get()); if (!pFileDefinitionWidgetDraw->isActive()) { m_pWidgetDraw.reset(); return false; } return true; } return false; } SalGraphics::~SalGraphics() COVERITY_NOEXCEPT_FALSE { // can't call ReleaseFonts here, as the destructor just calls this classes SetFont (pure virtual)! } bool SalGraphics::drawTransformedBitmap( const basegfx::B2DPoint& /* rNull */, const basegfx::B2DPoint& /* rX */, const basegfx::B2DPoint& /* rY */, const SalBitmap& /* rSourceBitmap */, const SalBitmap* /* pAlphaBitmap */, double /* fAlpha */) { // here direct support for transformed bitmaps can be implemented return false; } tools::Long SalGraphics::mirror2( tools::Long x, const OutputDevice& rOutDev ) const { mirror(x, rOutDev); return x; } inline tools::Long SalGraphics::GetDeviceWidth(const OutputDevice& rOutDev) const { return rOutDev.IsVirtual() ? rOutDev.GetOutputWidthPixel() : GetGraphicsWidth(); } void SalGraphics::mirror( tools::Long& x, const OutputDevice& rOutDev ) const { const tools::Long w = GetDeviceWidth(rOutDev); if( !w ) return; if (rOutDev.ImplIsAntiparallel() ) { // mirror this window back if( m_nLayout & SalLayoutFlags::BiDiRtl ) { tools::Long devX = w - rOutDev.GetOutputWidthPixel() - rOutDev.GetOutOffXPixel(); // re-mirrored mnOutOffX x = devX + (x - rOutDev.GetOutOffXPixel()); } else { tools::Long devX = rOutDev.GetOutOffXPixel(); // re-mirrored mnOutOffX x = rOutDev.GetOutputWidthPixel() - (x - devX) + rOutDev.GetOutOffXPixel() - 1; } } else if( m_nLayout & SalLayoutFlags::BiDiRtl ) x = w-1-x; } void SalGraphics::mirror( tools::Long& x, tools::Long nWidth, const OutputDevice& rOutDev, bool bBack ) const { const tools::Long w = GetDeviceWidth(rOutDev); if( !w ) return; if (rOutDev.ImplIsAntiparallel() ) { // mirror this window back if( m_nLayout & SalLayoutFlags::BiDiRtl ) { tools::Long devX = w - rOutDev.GetOutputWidthPixel() - rOutDev.GetOutOffXPixel(); // re-mirrored mnOutOffX if( bBack ) x = x - devX + rOutDev.GetOutOffXPixel(); else x = devX + (x - rOutDev.GetOutOffXPixel()); } else { tools::Long devX = rOutDev.GetOutOffXPixel(); // re-mirrored mnOutOffX if( bBack ) x = devX + (rOutDev.GetOutputWidthPixel() + devX) - (x + nWidth); else x = rOutDev.GetOutputWidthPixel() - (x - devX) + rOutDev.GetOutOffXPixel() - nWidth; } } else if( m_nLayout & SalLayoutFlags::BiDiRtl ) x = w-nWidth-x; } bool SalGraphics::mirror( sal_uInt32 nPoints, const Point *pPtAry, Point *pPtAry2, const OutputDevice& rOutDev ) const { const tools::Long w = GetDeviceWidth(rOutDev); if( w ) { sal_uInt32 i, j; if (rOutDev.ImplIsAntiparallel()) { // mirror this window back if( m_nLayout & SalLayoutFlags::BiDiRtl ) { tools::Long devX = w - rOutDev.GetOutputWidthPixel() - rOutDev.GetOutOffXPixel(); // re-mirrored mnOutOffX for( i=0, j=nPoints-1; i(this)->m_nLastMirrorTranslation = nTranslate; const_cast(this)->m_eLastMirrorMode = eNewMirrorMode; switch (eNewMirrorMode) { // mirror this window back case MirrorMode::AntiparallelBiDi: { /* This path gets exercised in calc's RTL UI (e.g. SAL_RTL_ENABLED=1) with its LTR horizontal scrollbar */ // Original code was: // double devX = w-i_rOutDev.GetOutputWidthPixel()-i_rOutDev.GetOutOffXPixel(); // re-mirrored mnOutOffX // aRet.setX( devX + (i_rPoint.getX() - i_rOutDev.GetOutOffXPixel()) ); const_cast(this)->m_aLastMirror = basegfx::utils::createTranslateB2DHomMatrix( nTranslate, 0.0); break; } case MirrorMode::Antiparallel: { /* This path gets exercised in writers's LTR UI with a RTL horizontal scrollbar, cross-reference dialog populated from contents from a RTL document tdf#131725 */ // Original code was; // tools::Long devX = rOutDev.GetOutOffXPixel(); // re-mirrored mnOutOffX // x = rOutDev.GetOutputWidthPixel() - (x - devX) + rOutDev.GetOutOffXPixel() - 1; const_cast(this)->m_aLastMirror = basegfx::utils::createScaleTranslateB2DHomMatrix( -1.0, 1.0, nTranslate, 0.0); break; } case MirrorMode::BiDi: { // Original code was: // aRet.setX( w-1-i_rPoint.getX() ); // -mirror X -> scale(-1.0, 1.0) // -translate X -> translate(w-1, 0) // Checked this one, works as expected. const_cast(this)->m_aLastMirror = basegfx::utils::createScaleTranslateB2DHomMatrix( -1.0, 1.0, nTranslate, 0.0); break; } case MirrorMode::NONE: const_cast(this)->m_aLastMirror.identity(); break; } } return m_aLastMirror; } bool SalGraphics::SetClipRegion( const vcl::Region& i_rClip, const OutputDevice& rOutDev ) { if( (m_nLayout & SalLayoutFlags::BiDiRtl) || rOutDev.IsRTLEnabled() ) { vcl::Region aMirror( i_rClip ); mirror( aMirror, rOutDev ); return setClipRegion( aMirror ); } return setClipRegion( i_rClip ); } void SalGraphics::DrawPixel( tools::Long nX, tools::Long nY, const OutputDevice& rOutDev ) { if( (m_nLayout & SalLayoutFlags::BiDiRtl) || rOutDev.IsRTLEnabled() ) mirror( nX, rOutDev ); drawPixel( nX, nY ); } void SalGraphics::DrawPixel( tools::Long nX, tools::Long nY, Color nColor, const OutputDevice& rOutDev ) { if( (m_nLayout & SalLayoutFlags::BiDiRtl) || rOutDev.IsRTLEnabled() ) mirror( nX, rOutDev ); drawPixel( nX, nY, nColor ); } void SalGraphics::DrawLine( tools::Long nX1, tools::Long nY1, tools::Long nX2, tools::Long nY2, const OutputDevice& rOutDev ) { if( (m_nLayout & SalLayoutFlags::BiDiRtl) || rOutDev.IsRTLEnabled() ) { mirror( nX1, rOutDev ); mirror( nX2, rOutDev ); } drawLine( nX1, nY1, nX2, nY2 ); } void SalGraphics::DrawRect( tools::Long nX, tools::Long nY, tools::Long nWidth, tools::Long nHeight, const OutputDevice& rOutDev ) { if( (m_nLayout & SalLayoutFlags::BiDiRtl) || rOutDev.IsRTLEnabled() ) mirror( nX, nWidth, rOutDev ); drawRect( nX, nY, nWidth, nHeight ); } void SalGraphics::DrawPolyLine( sal_uInt32 nPoints, Point const * pPtAry, const OutputDevice& rOutDev ) { if( (m_nLayout & SalLayoutFlags::BiDiRtl) || rOutDev.IsRTLEnabled() ) { std::unique_ptr pPtAry2(new Point[nPoints]); bool bCopied = mirror( nPoints, pPtAry, pPtAry2.get(), rOutDev ); drawPolyLine( nPoints, bCopied ? pPtAry2.get() : pPtAry ); } else drawPolyLine( nPoints, pPtAry ); } void SalGraphics::DrawPolygon( sal_uInt32 nPoints, const Point* pPtAry, const OutputDevice& rOutDev ) { if( (m_nLayout & SalLayoutFlags::BiDiRtl) || rOutDev.IsRTLEnabled() ) { std::unique_ptr pPtAry2(new Point[nPoints]); bool bCopied = mirror( nPoints, pPtAry, pPtAry2.get(), rOutDev ); drawPolygon( nPoints, bCopied ? pPtAry2.get() : pPtAry ); } else drawPolygon( nPoints, pPtAry ); } void SalGraphics::DrawPolyPolygon( sal_uInt32 nPoly, const sal_uInt32* pPoints, const Point** pPtAry, const OutputDevice& rOutDev ) { if( (m_nLayout & SalLayoutFlags::BiDiRtl) || rOutDev.IsRTLEnabled() ) { // TODO: optimize, reduce new/delete calls std::unique_ptr pPtAry2( new Point*[nPoly] ); sal_uLong i; for(i=0; i(pPtAry2.get()) ); for(i=0; i pPtAry2(new Point[nPoints]); bool bCopied = mirror( nPoints, pPtAry, pPtAry2.get(), rOutDev ); bResult = drawPolyLineBezier( nPoints, bCopied ? pPtAry2.get() : pPtAry, pFlgAry ); } else bResult = drawPolyLineBezier( nPoints, pPtAry, pFlgAry ); return bResult; } bool SalGraphics::DrawPolygonBezier( sal_uInt32 nPoints, const Point* pPtAry, const PolyFlags* pFlgAry, const OutputDevice& rOutDev ) { bool bResult = false; if( (m_nLayout & SalLayoutFlags::BiDiRtl) || rOutDev.IsRTLEnabled() ) { std::unique_ptr pPtAry2(new Point[nPoints]); bool bCopied = mirror( nPoints, pPtAry, pPtAry2.get(), rOutDev ); bResult = drawPolygonBezier( nPoints, bCopied ? pPtAry2.get() : pPtAry, pFlgAry ); } else bResult = drawPolygonBezier( nPoints, pPtAry, pFlgAry ); return bResult; } bool SalGraphics::DrawPolyPolygonBezier( sal_uInt32 i_nPoly, const sal_uInt32* i_pPoints, const Point* const* i_pPtAry, const PolyFlags* const* i_pFlgAry, const OutputDevice& i_rOutDev ) { bool bRet = false; if( (m_nLayout & SalLayoutFlags::BiDiRtl) || i_rOutDev.IsRTLEnabled() ) { // TODO: optimize, reduce new/delete calls std::unique_ptr pPtAry2( new Point*[i_nPoly] ); sal_uLong i; for(i=0; i(pPtAry2.get()), i_pFlgAry ); for(i=0; i* i_pStroke, // MM01 basegfx::B2DLineJoin i_eLineJoin, css::drawing::LineCap i_eLineCap, double i_fMiterMinimumAngle, bool bPixelSnapHairline, const OutputDevice& i_rOutDev) { if( (m_nLayout & SalLayoutFlags::BiDiRtl) || i_rOutDev.IsRTLEnabled() ) { // mirroring set const basegfx::B2DHomMatrix& rMirror(getMirror(i_rOutDev)); if(!rMirror.isIdentity()) { return drawPolyLine( rMirror * rObjectToDevice, i_rPolygon, i_fTransparency, i_rLineWidth, i_pStroke, // MM01 i_eLineJoin, i_eLineCap, i_fMiterMinimumAngle, bPixelSnapHairline); } } // no mirroring set (or identity), use standard call return drawPolyLine( rObjectToDevice, i_rPolygon, i_fTransparency, i_rLineWidth, i_pStroke, // MM01 i_eLineJoin, i_eLineCap, i_fMiterMinimumAngle, bPixelSnapHairline); } bool SalGraphics::DrawGradient(const tools::PolyPolygon& rPolyPoly, const Gradient& rGradient, const OutputDevice& rOutDev) { if( (m_nLayout & SalLayoutFlags::BiDiRtl) || rOutDev.IsRTLEnabled() ) { tools::PolyPolygon aMirrored(mirror(rPolyPoly.getB2DPolyPolygon(), rOutDev)); return drawGradient(aMirrored, rGradient); } return drawGradient( rPolyPoly, rGradient ); } void SalGraphics::CopyArea( tools::Long nDestX, tools::Long nDestY, tools::Long nSrcX, tools::Long nSrcY, tools::Long nSrcWidth, tools::Long nSrcHeight, const OutputDevice& rOutDev ) { if( (m_nLayout & SalLayoutFlags::BiDiRtl) || rOutDev.IsRTLEnabled() ) { mirror( nDestX, nSrcWidth, rOutDev ); mirror( nSrcX, nSrcWidth, rOutDev ); } copyArea( nDestX, nDestY, nSrcX, nSrcY, nSrcWidth, nSrcHeight, true/*bWindowInvalidate*/ ); } void SalGraphics::CopyBits(const SalTwoRect& rPosAry, const OutputDevice& rOutDev) { if( (m_nLayout & SalLayoutFlags::BiDiRtl) || rOutDev.IsRTLEnabled() ) { SalTwoRect aPosAry2 = rPosAry; mirror( aPosAry2.mnDestX, aPosAry2.mnDestWidth, rOutDev ); copyBits( aPosAry2, nullptr ); } else copyBits( rPosAry, nullptr ); } void SalGraphics::CopyBits(const SalTwoRect& rPosAry, SalGraphics& rSrcGraphics, const OutputDevice& rOutDev, const OutputDevice& rSrcOutDev) { if( ( (m_nLayout & SalLayoutFlags::BiDiRtl) || rOutDev.IsRTLEnabled() ) || ( (rSrcGraphics.GetLayout() & SalLayoutFlags::BiDiRtl) || rSrcOutDev.IsRTLEnabled()) ) { SalTwoRect aPosAry2 = rPosAry; if( (rSrcGraphics.GetLayout() & SalLayoutFlags::BiDiRtl) || rSrcOutDev.IsRTLEnabled() ) mirror( aPosAry2.mnSrcX, aPosAry2.mnSrcWidth, rSrcOutDev ); if( (m_nLayout & SalLayoutFlags::BiDiRtl) || rOutDev.IsRTLEnabled() ) mirror( aPosAry2.mnDestX, aPosAry2.mnDestWidth, rOutDev ); copyBits( aPosAry2, &rSrcGraphics ); } else copyBits( rPosAry, &rSrcGraphics ); } void SalGraphics::DrawBitmap( const SalTwoRect& rPosAry, const SalBitmap& rSalBitmap, const OutputDevice& rOutDev ) { if( (m_nLayout & SalLayoutFlags::BiDiRtl) || rOutDev.IsRTLEnabled() ) { SalTwoRect aPosAry2 = rPosAry; mirror( aPosAry2.mnDestX, aPosAry2.mnDestWidth, rOutDev ); drawBitmap( aPosAry2, rSalBitmap ); } else drawBitmap( rPosAry, rSalBitmap ); } void SalGraphics::DrawBitmap( const SalTwoRect& rPosAry, const SalBitmap& rSalBitmap, const SalBitmap& rTransparentBitmap, const OutputDevice& rOutDev ) { if( (m_nLayout & SalLayoutFlags::BiDiRtl) || rOutDev.IsRTLEnabled() ) { SalTwoRect aPosAry2 = rPosAry; mirror( aPosAry2.mnDestX, aPosAry2.mnDestWidth, rOutDev ); drawBitmap( aPosAry2, rSalBitmap, rTransparentBitmap ); } else drawBitmap( rPosAry, rSalBitmap, rTransparentBitmap ); } void SalGraphics::DrawMask( const SalTwoRect& rPosAry, const SalBitmap& rSalBitmap, Color nMaskColor, const OutputDevice& rOutDev ) { if( (m_nLayout & SalLayoutFlags::BiDiRtl) || rOutDev.IsRTLEnabled() ) { SalTwoRect aPosAry2 = rPosAry; mirror( aPosAry2.mnDestX, aPosAry2.mnDestWidth, rOutDev ); drawMask( aPosAry2, rSalBitmap, nMaskColor ); } else drawMask( rPosAry, rSalBitmap, nMaskColor ); } std::shared_ptr SalGraphics::GetBitmap( tools::Long nX, tools::Long nY, tools::Long nWidth, tools::Long nHeight, const OutputDevice& rOutDev ) { if( (m_nLayout & SalLayoutFlags::BiDiRtl) || rOutDev.IsRTLEnabled() ) mirror( nX, nWidth, rOutDev ); return getBitmap( nX, nY, nWidth, nHeight ); } Color SalGraphics::GetPixel( tools::Long nX, tools::Long nY, const OutputDevice& rOutDev ) { if( (m_nLayout & SalLayoutFlags::BiDiRtl) || rOutDev.IsRTLEnabled() ) mirror( nX, rOutDev ); return getPixel( nX, nY ); } void SalGraphics::Invert( tools::Long nX, tools::Long nY, tools::Long nWidth, tools::Long nHeight, SalInvert nFlags, const OutputDevice& rOutDev ) { if( (m_nLayout & SalLayoutFlags::BiDiRtl) || rOutDev.IsRTLEnabled() ) mirror( nX, nWidth, rOutDev ); invert( nX, nY, nWidth, nHeight, nFlags ); } void SalGraphics::Invert( sal_uInt32 nPoints, const Point* pPtAry, SalInvert nFlags, const OutputDevice& rOutDev ) { if( (m_nLayout & SalLayoutFlags::BiDiRtl) || rOutDev.IsRTLEnabled() ) { std::unique_ptr pPtAry2(new Point[nPoints]); bool bCopied = mirror( nPoints, pPtAry, pPtAry2.get(), rOutDev ); invert( nPoints, bCopied ? pPtAry2.get() : pPtAry, nFlags ); } else invert( nPoints, pPtAry, nFlags ); } bool SalGraphics::DrawEPS( tools::Long nX, tools::Long nY, tools::Long nWidth, tools::Long nHeight, void* pPtr, sal_uInt32 nSize, const OutputDevice& rOutDev ) { if( (m_nLayout & SalLayoutFlags::BiDiRtl) || rOutDev.IsRTLEnabled() ) mirror( nX, nWidth, rOutDev ); return drawEPS( nX, nY, nWidth, nHeight, pPtr, nSize ); } bool SalGraphics::HitTestNativeScrollbar(ControlPart nPart, const tools::Rectangle& rControlRegion, const Point& aPos, bool& rIsInside, const OutputDevice& rOutDev) { if( (m_nLayout & SalLayoutFlags::BiDiRtl) || rOutDev.IsRTLEnabled() ) { Point pt( aPos ); tools::Rectangle rgn( rControlRegion ); pt.setX( mirror2( pt.X(), rOutDev ) ); mirror( rgn, rOutDev ); return forWidget()->hitTestNativeControl( ControlType::Scrollbar, nPart, rgn, pt, rIsInside ); } else return forWidget()->hitTestNativeControl( ControlType::Scrollbar, nPart, rControlRegion, aPos, rIsInside ); } void SalGraphics::mirror( ImplControlValue& rVal, const OutputDevice& rOutDev ) const { switch( rVal.getType() ) { case ControlType::Slider: { SliderValue* pSlVal = static_cast(&rVal); mirror(pSlVal->maThumbRect, rOutDev); } break; case ControlType::Scrollbar: { ScrollbarValue* pScVal = static_cast(&rVal); mirror(pScVal->maThumbRect, rOutDev); mirror(pScVal->maButton1Rect, rOutDev); mirror(pScVal->maButton2Rect, rOutDev); } break; case ControlType::Spinbox: case ControlType::SpinButtons: { SpinbuttonValue* pSpVal = static_cast(&rVal); mirror(pSpVal->maUpperRect, rOutDev); mirror(pSpVal->maLowerRect, rOutDev); } break; case ControlType::Toolbar: { ToolbarValue* pTVal = static_cast(&rVal); mirror(pTVal->maGripRect, rOutDev); } break; default: break; } } bool SalGraphics::DrawNativeControl( ControlType nType, ControlPart nPart, const tools::Rectangle& rControlRegion, ControlState nState, const ImplControlValue& aValue, const OUString& aCaption, const OutputDevice& rOutDev, const Color& rBackgroundColor) { bool bRet = false; tools::Rectangle aControlRegion(rControlRegion); if (aControlRegion.IsEmpty() || aControlRegion.GetWidth() <= 0 || aControlRegion.GetHeight() <= 0) return bRet; bool bLayoutRTL = true && (m_nLayout & SalLayoutFlags::BiDiRtl); bool bDevRTL = rOutDev.IsRTLEnabled(); bool bIsLOK = comphelper::LibreOfficeKit::isActive(); if( (bLayoutRTL || bDevRTL) && !bIsLOK ) { mirror(aControlRegion, rOutDev); std::unique_ptr< ImplControlValue > mirrorValue( aValue.clone()); mirror( *mirrorValue, rOutDev ); bRet = forWidget()->drawNativeControl(nType, nPart, aControlRegion, nState, *mirrorValue, aCaption, rBackgroundColor); } else bRet = forWidget()->drawNativeControl(nType, nPart, aControlRegion, nState, aValue, aCaption, rBackgroundColor); if (bRet && m_pWidgetDraw) handleDamage(aControlRegion); return bRet; } bool SalGraphics::GetNativeControlRegion( ControlType nType, ControlPart nPart, const tools::Rectangle& rControlRegion, ControlState nState, const ImplControlValue& aValue, tools::Rectangle &rNativeBoundingRegion, tools::Rectangle &rNativeContentRegion, const OutputDevice& rOutDev ) { if( (m_nLayout & SalLayoutFlags::BiDiRtl) || rOutDev.IsRTLEnabled() ) { tools::Rectangle rgn( rControlRegion ); mirror( rgn, rOutDev ); std::unique_ptr< ImplControlValue > mirrorValue( aValue.clone()); mirror( *mirrorValue, rOutDev ); if (forWidget()->getNativeControlRegion(nType, nPart, rgn, nState, *mirrorValue, OUString(), rNativeBoundingRegion, rNativeContentRegion)) { mirror( rNativeBoundingRegion, rOutDev, true ); mirror( rNativeContentRegion, rOutDev, true ); return true; } return false; } else return forWidget()->getNativeControlRegion(nType, nPart, rControlRegion, nState, aValue, OUString(), rNativeBoundingRegion, rNativeContentRegion); } bool SalGraphics::BlendBitmap( const SalTwoRect& rPosAry, const SalBitmap& rBitmap, const OutputDevice& rOutDev ) { if( (m_nLayout & SalLayoutFlags::BiDiRtl) || rOutDev.IsRTLEnabled() ) { SalTwoRect aPosAry2 = rPosAry; mirror( aPosAry2.mnDestX, aPosAry2.mnDestWidth, rOutDev ); return blendBitmap( aPosAry2, rBitmap ); } else return blendBitmap( rPosAry, rBitmap ); } bool SalGraphics::BlendAlphaBitmap( const SalTwoRect& rPosAry, const SalBitmap& rSrcBitmap, const SalBitmap& rMaskBitmap, const SalBitmap& rAlphaBitmap, const OutputDevice& rOutDev ) { if( (m_nLayout & SalLayoutFlags::BiDiRtl) || rOutDev.IsRTLEnabled() ) { SalTwoRect aPosAry2 = rPosAry; mirror( aPosAry2.mnDestX, aPosAry2.mnDestWidth, rOutDev ); return blendAlphaBitmap( aPosAry2, rSrcBitmap, rMaskBitmap, rAlphaBitmap ); } else return blendAlphaBitmap( rPosAry, rSrcBitmap, rMaskBitmap, rAlphaBitmap ); } bool SalGraphics::DrawAlphaBitmap( const SalTwoRect& rPosAry, const SalBitmap& rSourceBitmap, const SalBitmap& rAlphaBitmap, const OutputDevice& rOutDev ) { if( (m_nLayout & SalLayoutFlags::BiDiRtl) || rOutDev.IsRTLEnabled() ) { SalTwoRect aPosAry2 = rPosAry; mirror( aPosAry2.mnDestX, aPosAry2.mnDestWidth, rOutDev ); return drawAlphaBitmap( aPosAry2, rSourceBitmap, rAlphaBitmap ); } else return drawAlphaBitmap( rPosAry, rSourceBitmap, rAlphaBitmap ); } bool SalGraphics::DrawTransformedBitmap( const basegfx::B2DPoint& rNull, const basegfx::B2DPoint& rX, const basegfx::B2DPoint& rY, const SalBitmap& rSourceBitmap, const SalBitmap* pAlphaBitmap, double fAlpha, const OutputDevice& rOutDev) { if( (m_nLayout & SalLayoutFlags::BiDiRtl) || rOutDev.IsRTLEnabled() ) { // mirroring set const basegfx::B2DHomMatrix& rMirror(getMirror(rOutDev)); if (!rMirror.isIdentity()) { basegfx::B2DPolygon aPoints({rNull, rX, rY}); basegfx::B2DRange aBoundingBox(aPoints.getB2DRange()); auto aTranslateToMirroredBounds = createTranslateToMirroredBounds(aBoundingBox, rMirror); basegfx::B2DPoint aNull = aTranslateToMirroredBounds * rNull; basegfx::B2DPoint aX = aTranslateToMirroredBounds * rX; basegfx::B2DPoint aY = aTranslateToMirroredBounds * rY; return drawTransformedBitmap(aNull, aX, aY, rSourceBitmap, pAlphaBitmap, fAlpha); } } return drawTransformedBitmap(rNull, rX, rY, rSourceBitmap, pAlphaBitmap, fAlpha); } bool SalGraphics::HasFastDrawTransformedBitmap() const { return hasFastDrawTransformedBitmap(); } bool SalGraphics::DrawAlphaRect( tools::Long nX, tools::Long nY, tools::Long nWidth, tools::Long nHeight, sal_uInt8 nTransparency, const OutputDevice& rOutDev ) { if( (m_nLayout & SalLayoutFlags::BiDiRtl) || rOutDev.IsRTLEnabled() ) mirror( nX, nWidth, rOutDev ); return drawAlphaRect( nX, nY, nWidth, nHeight, nTransparency ); } OUString SalGraphics::getRenderBackendName() const { if (GetImpl()) return GetImpl()->getRenderBackendName(); return OUString(); } void SalGraphics::GetGlyphWidths(const vcl::AbstractTrueTypeFont& rTTF, const vcl::font::PhysicalFontFace& rFontFace, const bool bVertical, std::vector& rWidths, Ucs2UIntMap& rUnicodeEnc) { rWidths.clear(); rUnicodeEnc.clear(); const int nGlyphCount = rTTF.glyphCount(); if (nGlyphCount <= 0) return; FontCharMapRef xFCMap = rFontFace.GetFontCharMap(); if (!xFCMap.is() || !xFCMap->GetCharCount()) { SAL_WARN("vcl.fonts", "no charmap"); return; } rWidths.resize(nGlyphCount); std::vector aGlyphIds(nGlyphCount); for (int i = 0; i < nGlyphCount; i++) aGlyphIds[i] = static_cast(i); std::unique_ptr pGlyphMetrics = GetTTSimpleGlyphMetrics(&rTTF, aGlyphIds.data(), nGlyphCount, bVertical); if (pGlyphMetrics) { for (int i = 0; i < nGlyphCount; ++i) rWidths[i] = pGlyphMetrics[i]; pGlyphMetrics.reset(); } int nCharCount = xFCMap->GetCharCount(); sal_uInt32 nChar = xFCMap->GetFirstChar(); for (; --nCharCount >= 0; nChar = xFCMap->GetNextChar(nChar)) { if (nChar > 0xFFFF) continue; sal_Ucs nUcsChar = static_cast(nChar); sal_uInt32 nGlyph = xFCMap->GetGlyphIndex(nUcsChar); if (nGlyph > 0) rUnicodeEnc[nUcsChar] = nGlyph; } } bool SalGraphics::CreateTTFfontSubset(vcl::AbstractTrueTypeFont& rTTF, const OString& rSysPath, const bool bVertical, const sal_GlyphId* pGlyphIds, const sal_uInt8* pEncoding, sal_Int32* pGlyphWidths, const int nOrigGlyphCount) { // Multiple questions: // - Why is there a glyph limit? // MacOS used to handle 257 glyphs... // Also the much more complex PrintFontManager variant has this limit. // Also the very first implementation has the limit in // commit 8789ed701e98031f2a1657ea0dfd6f7a0b050992 // - Why doesn't the PrintFontManager care about the fake glyph? It // is used on all unx platforms to create the subset font. // - Should the SAL_WARN actually be asserts, like on MacOS? if (nOrigGlyphCount > 256) { SAL_WARN("vcl.fonts", "too many glyphs for subsetting"); return false; } int nGlyphCount = nOrigGlyphCount; sal_uInt16 aShortIDs[256]; sal_uInt8 aTempEncs[256]; // handle the undefined / first font glyph int nNotDef = -1, i; for (i = 0; i < nGlyphCount; ++i) { aTempEncs[i] = pEncoding[i]; aShortIDs[i] = static_cast(pGlyphIds[i]); if (!aShortIDs[i]) if (nNotDef < 0) nNotDef = i; } // nNotDef glyph must be in pos 0 => swap glyphids if (nNotDef != 0) { if (nNotDef < 0) { if (nGlyphCount == 256) { SAL_WARN("vcl.fonts", "too many glyphs for subsetting"); return false; } nNotDef = nGlyphCount++; } aShortIDs[nNotDef] = aShortIDs[0]; aTempEncs[nNotDef] = aTempEncs[0]; aShortIDs[0] = 0; aTempEncs[0] = 0; } if (pGlyphWidths) { std::unique_ptr pMetrics = GetTTSimpleGlyphMetrics(&rTTF, aShortIDs, nGlyphCount, bVertical); if (!pMetrics) return false; sal_uInt16 nNotDefAdv = pMetrics[0]; pMetrics[0] = pMetrics[nNotDef]; pMetrics[nNotDef] = nNotDefAdv; for (i = 0; i < nOrigGlyphCount; ++i) pGlyphWidths[i] = pMetrics[i]; pMetrics.reset(); } // write subset into destination file return (CreateTTFromTTGlyphs(&rTTF, rSysPath.getStr(), aShortIDs, aTempEncs, nGlyphCount) == vcl::SFErrCodes::Ok); } bool SalGraphics::CreateCFFfontSubset(const unsigned char* pFontBytes, int nByteLength, const OString& rSysPath, const sal_GlyphId* pGlyphIds, const sal_uInt8* pEncoding, sal_Int32* pGlyphWidths, int nGlyphCount, FontSubsetInfo& rInfo) { FILE* pOutFile = fopen(rSysPath.getStr(), "wb"); if (!pOutFile) return false; rInfo.LoadFont(FontType::CFF_FONT, pFontBytes, nByteLength); bool bRet = rInfo.CreateFontSubset(FontType::TYPE1_PFB, pOutFile, nullptr, pGlyphIds, pEncoding, nGlyphCount, pGlyphWidths); fclose(pOutFile); return bRet; } void SalGraphics::FillFontSubsetInfo(const vcl::TTGlobalFontInfo& rTTInfo, const OUString& pPSName, FontSubsetInfo& rInfo) { rInfo.m_aPSName = pPSName; rInfo.m_nFontType = FontType::SFNT_TTF; rInfo.m_aFontBBox = tools::Rectangle(Point(rTTInfo.xMin, rTTInfo.yMin), Point(rTTInfo.xMax, rTTInfo.yMax)); rInfo.m_nCapHeight = rTTInfo.yMax; // Well ... rInfo.m_nAscent = rTTInfo.winAscent; rInfo.m_nDescent = rTTInfo.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 = +rTTInfo.typoAscender; if (!rInfo.m_nAscent) rInfo.m_nAscent = +rTTInfo.ascender; if (!rInfo.m_nDescent) rInfo.m_nDescent = +rTTInfo.typoDescender; if (!rInfo.m_nDescent) rInfo.m_nDescent = -rTTInfo.descender; } bool SalGraphics::ShouldDownscaleIconsAtSurface(double* pScaleOut) const { if (pScaleOut) *pScaleOut = comphelper::LibreOfficeKit::getDPIScale(); return comphelper::LibreOfficeKit::isActive(); } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */