/* -*- 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 .
*/
// TODO: Scale will be set to 2.0f as default after implementation of full scaled display support . This will allow moving of // windows between non retina and retina displays without blurry text and graphics. Static variables have to be removed thereafter.
// Currently scaled display support is not implemented for bitmaps. This will cause a slight performance degradation on displays // with single precision. To preserve performance for now, window scaling is only activated if at least one display with double // precision is present. Moving windows between displays is then possible without blurry text and graphics too. Adapting window // scaling when displays are added while application is running is not supported.
float getWindowScaling()
{ // Related: tdf#147342 Any changes to this function must be copied to the // sk_app::GetBackingScaleFactor() function in the following file: // workdir/UnpackedTarball/skia/tools/sk_app/mac/WindowContextFactory_mac.h if (!bWindowScaling)
{
NSArray *aScreens = [NSScreen screens]; if (aScreens != nullptr)
{ for (NSScreen *aScreen : aScreens)
{ float fScale = [aScreen backingScaleFactor]; if (fScale > fWindowScale)
fWindowScale = fScale;
}
bWindowScaling = true;
} if( constchar* env = getenv("SAL_FORCE_HIDPI_SCALING"))
{
fWindowScale = atof(env);
bWindowScaling = true;
}
} return fWindowScale;
}
void resetWindowScaling()
{ // Related: tdf#147342 Force recalculation of the window scaling but keep // the previous window scaling as the minimum so that we don't lose the // resolution in cached images if a HiDPI monitor is disconnected and // then reconnected. #if HAVE_FEATURE_SKIA if ( SkiaHelper::isVCLSkiaEnabled() )
skwindow::ResetBackingScaleFactor(); #endif
bWindowScaling = false;
getWindowScaling();
}
} // end aqua
if (rReleaseLayer)
{ // copy original layer to resized layer if (maContextHolder.isSet())
{
CGContextDrawLayerAtPoint(maContextHolder.get(), CGPointZero, rReleaseLayer);
}
CGLayerRelease(rReleaseLayer);
}
if (maContextHolder.isSet())
{
CGContextTranslateCTM(maContextHolder.get(), 0, nScaledHeight);
CGContextScaleCTM(maContextHolder.get(), 1.0, -1.0);
CGContextSetFillColorSpace(maContextHolder.get(), GetSalData()->mxRGBSpace);
CGContextSetStrokeColorSpace(maContextHolder.get(), GetSalData()->mxRGBSpace); // apply a scale matrix so everything is auto-magically scaled
CGContextScaleCTM(maContextHolder.get(), fScale, fScale);
maContextHolder.saveState();
setState();
// re-enable XOR emulation for the new context if (mpXorEmulation)
mpXorEmulation->SetTarget(mnWidth, mnHeight, mnBitmapDepth, maContextHolder.get(), maLayer.get());
}
}
}
/** * Blit the contents of our internal maLayer state to the * associated window, if any; cf. drawRect event handling * on the frame.
*/ void AquaSalGraphics::UpdateWindow( NSRect& rRect )
{ if (!maShared.mpFrame)
{ return;
}
NSGraphicsContext* pContext = [NSGraphicsContext currentContext]; if (!pContext)
{
SAL_WARN_IF(!maShared.mpFrame->mbInitShow, "vcl", "UpdateWindow called with no NSGraphicsContext"); return;
}
CGImageRef img = nullptr;
CGPoint aImageOrigin = CGPointMake(0, 0); bool bImageFlipped = false; #if HAVE_FEATURE_SKIA if (SkiaHelper::isVCLSkiaEnabled())
{ // tdf#159175 no CGLayer is needed for an NSWindow when using Skia // Get a CGImageRef directly from the Skia/Raster surface and draw // that directly to the NSWindow. // Note: Skia/Metal will always return a null CGImageRef since it // draws directly to the NSWindow using the surface's CAMetalLayer.
AquaSkiaSalGraphicsImpl *pBackend = static_cast<AquaSkiaSalGraphicsImpl*>(mpBackend.get()); if (pBackend)
img = pBackend->createCGImageFromRasterSurface(rRect, aImageOrigin, bImageFlipped);
} else #else
(void)rRect; #endif if (maShared.maLayer.isSet())
{
maShared.applyXorContext();
if (img)
{ constfloat fScale = sal::aqua::getWindowScaling();
CGContextHolder rCGContextHolder([pContext CGContext]);
rCGContextHolder.saveState();
CGRect aRect = CGRectMake(aImageOrigin.x / fScale, aImageOrigin.y / fScale, CGImageGetWidth(img) / fScale, CGImageGetHeight(img) / fScale); if (bImageFlipped)
{ // Related: tdf#155092 translate Y coordinate of flipped images // When in live resize, the NSView's height may have changed before // the surface has been resized. This causes flipped content // to be drawn just above or below the top left corner of the view // so translate the Y coordinate using the NSView's height. // Use the NSView's bounds, not its frame, to properly handle // any rotation and/or scaling that might have been already // applied to the view.
NSView *pView = maShared.mpFrame->mpNSView; if (pView)
aRect.origin.y = [pView bounds].size.height - aRect.origin.y - aRect.size.height; elseif (maShared.maLayer.isSet())
aRect.origin.y = maShared.maLayer.getSizePoints().height - aRect.origin.y - aRect.size.height;
}
// tdf#163152 don't convert image's sRGB colorspace // Converting the image's colorspace to match the window's // colorspace causes more than an expected amount of color // saturation so let the window's underlying CGContext handle // any necessary colorspace conversion in CGContextDrawImage().
CGContextDrawImage(rCGContextHolder.get(), aRect, img);
rCGContextHolder.restoreState();
CGImageRelease(img);
} else
{
SAL_WARN_IF(!maShared.mpFrame->mbInitShow, "vcl", "UpdateWindow called on uneligible graphics");
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.