Diff
Modified: trunk/Source/WebCore/ChangeLog (269210 => 269211)
--- trunk/Source/WebCore/ChangeLog 2020-10-30 23:56:26 UTC (rev 269210)
+++ trunk/Source/WebCore/ChangeLog 2020-10-31 00:01:02 UTC (rev 269211)
@@ -1,3 +1,104 @@
+2020-10-29 Myles C. Maxfield <mmaxfi...@apple.com>
+
+ [Cocoa] [GPU Process] Perform image decoding of color fonts in the Web Process
+ https://bugs.webkit.org/show_bug.cgi?id=217506
+
+ Reviewed by Simon Fraser.
+
+ Core Text itself doesn't know how to draw things; it has to rely on Core Graphics to do that.
+ However, Core Graphics only understands the simplest of text drawing concepts; it doesn't understand
+ things like color fonts or emoji. Core Text sits between the application and Core Graphics, and is
+ responsible for splitting up an arbitrary draw command into individual simple pieces which Core
+ Graphics can understand. For example, when you ask Core Text to draw a string which is of the form
+ "outlines emoji outlines", Core Text will end up telling Core Graphics to draw the first outlines, then
+ draw the emoji image (using Core Graphics's normal image drawing routines), then draw the remaining
+ outlines.
+
+ This is exactly the same kind of filtering we want to do for the GPU Process. We want to be able to
+ separate out the glyphs which are rendered using outlines from the emoji glyphs which are rendered
+ using images. We want to handle the image glyphs ourself in WebKit using our own image drawing display
+ list facilities, which will cause images to be decoded in the Web Process, thereby increasing the
+ security of the GPU Process.
+
+ So, this patch implements a custom CGContext, backed by a function table that is populated in WebKit.
+ We pass this custom CGContext into Core Text, which does its normal splitting up of outlines / images,
+ and calls glyph / image drawing functions on our CGContext. Because these functions are implemented by
+ WebKit, this effectively makes WebKit able to intercept the drawing calls, and implement them ourself
+ by appending items to the current display list. So, when Core Text tells our CGContext to draw an emoji,
+ our callback runs and we "just" append a DrawImage display list item.
+
+ I use scare-quotes around "just" because it is a bit more complicated than that. Core Text internally
+ can change the fill/stroke color (for COLR glyphs), the text matrix (it should be updated between
+ adjacent runs), the CTM, and the shadow state (because Core Text sometimes will implement shadows itself
+ by just drawing the text two times). So, in our CGContext callback, we have to look at the state of
+ the CGContext, figure out if anything changed (because we're not notified when changes happen), and
+ if things did change, append additional display list items to make a parallel change happen at draw
+ time.
+
+ Tests added in https://trac.webkit.org/r269177
+
+ * Headers.cmake:
+ * PlatformAppleWin.cmake:
+ * PlatformWinCairo.cmake:
+ * SourcesCocoa.txt:
+ * WebCore.xcodeproj/project.pbxproj:
+ * platform/FreeType.cmake:
+ * platform/graphics/cg/ImageBufferCGBackend.cpp:
+ (WebCore::ImageBufferCGBackend::setupContext):
+ * platform/graphics/coretext/FontCascadeCoreText.cpp:
+ (WebCore::fillVectorWithHorizontalGlyphPositions):
+ * platform/graphics/displaylists/DisplayListDrawGlyphsRecorder.h: Added.
+ * platform/graphics/displaylists/DisplayListDrawGlyphsRecorderCoreText.cpp: Added.
+ (WebCore::DisplayList::beginLayer): VTable callback for creating a transparency layer.
+ (WebCore::DisplayList::endLayer): Ditto for ending a transparency layer.
+ (WebCore::DisplayList::drawGlyphs): VTable callback for drawing outline glyphs.
+ (WebCore::DisplayList::drawImage): VTable callback for drawing an image.
+ (WebCore::DisplayList::DrawGlyphsRecorder::createInternalContext): Set up the custom CGContext
+ infrastructure. Hook up the VTable callbacks.
+ (WebCore::DisplayList::DrawGlyphsRecorder::DrawGlyphsRecorder):
+ (WebCore::DisplayList::DrawGlyphsRecorder::populateInternalState): We need to save the GraphicsContext
+ state at the beginning of the entry point, so we can restore anything that changed when we're done.
+ (WebCore::DisplayList::DrawGlyphsRecorder::populateInternalContext): Because Core Text internally
+ interrogates the CGContext to see if it needs to do things like draw shadows itself, we need to make
+ sure that the recorder's state is mirrored in our custom CGContext. This applies all the relevant
+ state to our CGContext so it's ready when Core Text asks for it.
+ (WebCore::DisplayList::DrawGlyphsRecorder::prepareInternalContext): Call the above two functions.
+ (WebCore::DisplayList::DrawGlyphsRecorder::concludeInternalContext): Called once when we're done.
+ This function cleans up, by possibly appending additional display list items to restore the state
+ back to what it was when we started.
+ (WebCore::DisplayList::DrawGlyphsRecorder::updateFillColor): Detect a changed fill color, and if it has
+ changed, append a display list item to make a parallel change at drawing time.
+ (WebCore::DisplayList::DrawGlyphsRecorder::updateStrokeColor): Ditto for the stroke color.
+ (WebCore::DisplayList::DrawGlyphsRecorder::updateCTM): Ditto for the CTM.
+ (WebCore::DisplayList::shadowIsCleared):
+ (WebCore::DisplayList::DrawGlyphsRecorder::updateShadow): Ditto for the shadow state.
+ (WebCore::DisplayList::DrawGlyphsRecorder::recordBeginLayer): Hook this up to beginTransparencyLayer().
+ (WebCore::DisplayList::DrawGlyphsRecorder::recordEndLayer): Hook this up to endTransparencyLayer().
+ (WebCore::DisplayList::computeAdvancesFromPositions): CGContext gives us positions, but our display list
+ infrastructure requires advances. Simply subtract to convert between them.
+ (WebCore::DisplayList::DrawGlyphsRecorder::recordDrawGlyphs): The callback that appends a DrawGlyphs
+ display list item. Note it has to call the various update() functions to detect changes in the CGContext
+ state.
+ (WebCore::DisplayList::DrawGlyphsRecorder::recordDrawImage): Ditto for a DrawImage display list item.
+ (WebCore::DisplayList::DrawGlyphsRecorder::drawGlyphs): The main entry point. Simply set up, do the work,
+ then clean up.
+ * platform/graphics/displaylists/DisplayListDrawGlyphsRecorderHarfBuzz.cpp: Added. Dummy implementation
+ to make the other ports continue to compile.
+ (WebCore::DisplayList::DrawGlyphsRecorder::DrawGlyphsRecorder):
+ (WebCore::DisplayList::DrawGlyphsRecorder::drawGlyphs):
+ * platform/graphics/displaylists/DisplayListRecorder.cpp:
+ (WebCore::DisplayList::Recorder::Recorder):
+ (WebCore::DisplayList::Recorder::drawGlyphs): Call m_drawGlyphsRecorder.drawGlyphs() instead of just
+ appending a DrawGlyphs command.
+ (WebCore::DisplayList::Recorder::concatCTM): Tiny optimization.
+ (WebCore::DisplayList::Recorder::clipToDrawingCommands): The current clipToDrawingCommands's context
+ CTM didn't match the parallel one used during playback. In order to make the CTMs match are recording
+ and playback time, we have to make sure they start off the same.
+ * platform/graphics/displaylists/DisplayListRecorder.h: DisplayList::Recorder owns a DrawGlyphsRecorder,
+ whose lifetime equals that of the DisplayList::Recorder. Rather than destroying / recreating the
+ DrawGlyphsRecorder, the DrawGlyphsRecorder class is smart enough to clean up after itself so it can be
+ reused multiple times.
+
2020-10-30 Brian Burg <bb...@apple.com>
Web Inspector: move InspectorFrontendAPIDispatcher to WebCore, clean up uses
Modified: trunk/Source/WebCore/Headers.cmake (269210 => 269211)
--- trunk/Source/WebCore/Headers.cmake 2020-10-30 23:56:26 UTC (rev 269210)
+++ trunk/Source/WebCore/Headers.cmake 2020-10-31 00:01:02 UTC (rev 269211)
@@ -1238,6 +1238,7 @@
platform/graphics/angle/ExtensionsGLANGLE.h
platform/graphics/displaylists/DisplayList.h
+ platform/graphics/displaylists/DisplayListDrawGlyphsRecorder.h
platform/graphics/displaylists/DisplayListDrawingContext.h
platform/graphics/displaylists/DisplayListImageBuffer.h
platform/graphics/displaylists/DisplayListItems.h
Modified: trunk/Source/WebCore/PAL/ChangeLog (269210 => 269211)
--- trunk/Source/WebCore/PAL/ChangeLog 2020-10-30 23:56:26 UTC (rev 269210)
+++ trunk/Source/WebCore/PAL/ChangeLog 2020-10-31 00:01:02 UTC (rev 269211)
@@ -1,3 +1,14 @@
+2020-10-29 Myles C. Maxfield <mmaxfi...@apple.com>
+
+ [Cocoa] [GPU Process] Perform image decoding of color fonts in the Web Process
+ https://bugs.webkit.org/show_bug.cgi?id=217506
+
+ Reviewed by Simon Fraser.
+
+ Add some new entry points, and do some various cleanup.
+
+ * pal/spi/cg/CoreGraphicsSPI.h:
+
2020-10-30 Chris Fleizach <cfleiz...@apple.com>
AX: Incorrect list of voices being displayed on iOS
Modified: trunk/Source/WebCore/PAL/pal/spi/cg/CoreGraphicsSPI.h (269210 => 269211)
--- trunk/Source/WebCore/PAL/pal/spi/cg/CoreGraphicsSPI.h 2020-10-30 23:56:26 UTC (rev 269210)
+++ trunk/Source/WebCore/PAL/pal/spi/cg/CoreGraphicsSPI.h 2020-10-31 00:01:02 UTC (rev 269211)
@@ -38,6 +38,7 @@
#if USE(APPLE_INTERNAL_SDK)
+#include <CoreGraphics/CGContextDelegatePrivate.h>
#include <CoreGraphics/CGFontCache.h>
#include <CoreGraphics/CGPathPrivate.h>
#include <CoreGraphics/CoreGraphicsPrivate.h>
@@ -58,19 +59,12 @@
int minRightSideBearing;
};
-struct CGFontDescriptor {
- CGRect bbox;
- CGFloat ascent;
- CGFloat descent;
- CGFloat capHeight;
- CGFloat italicAngle;
- CGFloat stemV;
- CGFloat stemH;
- CGFloat avgWidth;
- CGFloat maxWidth;
- CGFloat missingWidth;
- CGFloat leading;
- CGFloat xHeight;
+typedef CF_ENUM (int32_t, CGContextDelegateCallbackName)
+{
+ deDrawImage = 7,
+ deDrawGlyphs = 8,
+ deBeginLayer = 17,
+ deEndLayer = 18,
};
typedef const struct CGColorTransform* CGColorTransformRef;
@@ -179,6 +173,22 @@
#endif // PLATFORM(COCOA)
+struct CGShadowStyle {
+ unsigned a;
+ CGFloat b;
+ CGFloat azimuth;
+ CGFloat c;
+ CGFloat height;
+ CGFloat radius;
+ CGFloat d;
+};
+typedef struct CGShadowStyle CGShadowStyle;
+
+typedef CF_ENUM (int32_t, CGStyleType)
+{
+ kCGStyleShadow = 1,
+};
+
#if PLATFORM(MAC)
typedef CF_ENUM(uint32_t, CGSNotificationType) {
@@ -193,6 +203,12 @@
#endif // PLATFORM(MAC)
+typedef struct CGContextDelegate *CGContextDelegateRef;
+typedef void (*CGContextDelegateCallback)(void);
+typedef struct CGRenderingState *CGRenderingStateRef;
+typedef struct CGGState *CGGStateRef;
+typedef struct CGStyle *CGStyleRef;
+
#endif // USE(APPLE_INTERNAL_SDK)
#if PLATFORM(COCOA)
@@ -203,7 +219,6 @@
typedef CGSWindowID* CGSWindowIDList;
typedef struct CF_BRIDGED_TYPE(id) CGSRegionObject* CGSRegionObj;
-typedef struct CF_BRIDGED_TYPE(id) CGStyle* CGStyleRef;
typedef void* CGSNotificationArg;
typedef void* CGSNotificationData;
@@ -233,7 +248,6 @@
CGContextType CGContextGetType(CGContextRef);
CFStringRef CGFontCopyFamilyName(CGFontRef);
-bool CGFontGetDescriptor(CGFontRef, CGFontDescriptor*);
bool CGFontGetGlyphAdvancesForStyle(CGFontRef, const CGAffineTransform* , CGFontRenderingStyle, const CGGlyph[], size_t count, CGSize advances[]);
void CGFontGetGlyphsForUnichars(CGFontRef, const UniChar[], CGGlyph[], size_t count);
const CGFontHMetrics* CGFontGetHMetrics(CGFontRef);
@@ -252,6 +266,21 @@
bool CGContextDrawsWithCorrectShadowOffsets(CGContextRef);
CGPatternRef CGPatternCreateWithImage2(CGImageRef, CGAffineTransform, CGPatternTiling);
+CGContextDelegateRef CGContextDelegateCreate(void* info);
+void CGContextDelegateSetCallback(CGContextDelegateRef, CGContextDelegateCallbackName, CGContextDelegateCallback);
+CGContextRef CGContextCreateWithDelegate(CGContextDelegateRef, CGContextType, CGRenderingStateRef, CGGStateRef);
+void* CGContextDelegateGetInfo(CGContextDelegateRef);
+void CGContextDelegateRelease(CGContextDelegateRef);
+CGFloat CGGStateGetAlpha(CGGStateRef);
+CGFontRef CGGStateGetFont(CGGStateRef);
+const CGAffineTransform *CGGStateGetCTM(CGGStateRef);
+CGColorRef CGGStateGetFillColor(CGGStateRef);
+CGColorRef CGGStateGetStrokeColor(CGGStateRef);
+CGStyleRef CGGStateGetStyle(CGGStateRef);
+CGStyleType CGStyleGetType(CGStyleRef);
+const void *CGStyleGetData(CGStyleRef);
+CGColorRef CGStyleGetColor(CGStyleRef);
+
#if HAVE(CGPATH_GET_NUMBER_OF_ELEMENTS)
size_t CGPathGetNumberOfElements(CGPathRef);
#endif
@@ -286,16 +315,9 @@
CGSRegionEnumeratorObj CGSRegionEnumerator(CGRegionRef);
CGStyleRef CGStyleCreateFocusRingWithColor(const CGFocusRingStyle*, CGColorRef);
void CGContextSetStyle(CGContextRef, CGStyleRef);
-
void CGContextDrawConicGradient(CGContextRef, CGGradientRef, CGPoint center, CGFloat angle);
-
-#if HAVE(CG_PATH_UNEVEN_CORNERS_ROUNDEDRECT)
void CGPathAddUnevenCornersRoundedRect(CGMutablePathRef, const CGAffineTransform *, CGRect, const CGSize corners[4]);
-#endif
-
-#if HAVE(CG_FONT_RENDERING_GET_FONT_SMOOTHING_DISABLED)
bool CGFontRenderingGetFontSmoothingDisabled(void);
-#endif
#endif // PLATFORM(COCOA)
@@ -328,15 +350,10 @@
size_t CGDisplayModeGetPixelsWide(CGDisplayModeRef);
size_t CGDisplayModeGetPixelsHigh(CGDisplayModeRef);
-#if ENABLE(WEBPROCESS_WINDOWSERVER_BLOCKING)
-
CGError CGSSetDenyWindowServerConnections(bool);
-
typedef int32_t CGSDisplayID;
CGSDisplayID CGSMainDisplayID(void);
-#endif // ENABLE(WEBPROCESS_WINDOWSERVER_BLOCKING)
-
#endif // PLATFORM(MAC)
#if ENABLE(PDFKIT_PLUGIN) && !USE(APPLE_INTERNAL_SDK)
Modified: trunk/Source/WebCore/PlatformAppleWin.cmake (269210 => 269211)
--- trunk/Source/WebCore/PlatformAppleWin.cmake 2020-10-30 23:56:26 UTC (rev 269210)
+++ trunk/Source/WebCore/PlatformAppleWin.cmake 2020-10-31 00:01:02 UTC (rev 269211)
@@ -30,6 +30,8 @@
platform/graphics/avfoundation/cf/MediaPlayerPrivateAVFoundationCF.cpp
platform/graphics/avfoundation/cf/WebCoreAVCFResourceLoader.cpp
+ platform/graphics/displaylists/DisplayListDrawGlyphsRecorderWin.cpp
+
platform/graphics/win/FontCustomPlatformData.cpp
platform/network/cf/AuthenticationCF.cpp
Modified: trunk/Source/WebCore/PlatformWinCairo.cmake (269210 => 269211)
--- trunk/Source/WebCore/PlatformWinCairo.cmake 2020-10-30 23:56:26 UTC (rev 269210)
+++ trunk/Source/WebCore/PlatformWinCairo.cmake 2020-10-31 00:01:02 UTC (rev 269211)
@@ -22,6 +22,8 @@
platform/graphics/GLContext.cpp
platform/graphics/PlatformDisplay.cpp
+ platform/graphics/displaylists/DisplayListDrawGlyphsRecorderHarfBuzz.cpp
+
platform/graphics/win/FontCustomPlatformDataCairo.cpp
platform/graphics/win/FontPlatformDataCairoWin.cpp
platform/graphics/win/GlyphPageTreeNodeCairoWin.cpp
Modified: trunk/Source/WebCore/SourcesCocoa.txt (269210 => 269211)
--- trunk/Source/WebCore/SourcesCocoa.txt 2020-10-30 23:56:26 UTC (rev 269210)
+++ trunk/Source/WebCore/SourcesCocoa.txt 2020-10-31 00:01:02 UTC (rev 269211)
@@ -379,6 +379,7 @@
platform/graphics/cv/PixelBufferConformerCV.cpp
platform/graphics/cv/VideoTextureCopierCV.cpp
platform/graphics/coreimage/FilterEffectRendererCoreImage.mm
+platform/graphics/displaylists/DisplayListDrawGlyphsRecorderCoreText.cpp
platform/graphics/gpu/TilingData.cpp
platform/graphics/gpu/cocoa/GPUBindGroupAllocatorMetal.mm
platform/graphics/gpu/cocoa/GPUBindGroupLayoutMetal.mm
Modified: trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj (269210 => 269211)
--- trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj 2020-10-30 23:56:26 UTC (rev 269210)
+++ trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj 2020-10-31 00:01:02 UTC (rev 269211)
@@ -620,6 +620,7 @@
1CAF34810A6C405200ABE06E /* WebScriptObject.h in Headers */ = {isa = PBXBuildFile; fileRef = 1CAF347E0A6C405200ABE06E /* WebScriptObject.h */; settings = {ATTRIBUTES = (Private, ); }; };
1CAF34820A6C405200ABE06E /* WebScriptObject.mm in Sources */ = {isa = PBXBuildFile; fileRef = 1CAF347F0A6C405200ABE06E /* WebScriptObject.mm */; };
1CAF34830A6C405200ABE06E /* WebScriptObjectPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1CAF34800A6C405200ABE06E /* WebScriptObjectPrivate.h */; settings = {ATTRIBUTES = (Private, ); }; };
+ 1CAF56DB25301AC80017B472 /* DisplayListDrawGlyphsRecorder.h in Headers */ = {isa = PBXBuildFile; fileRef = 1CAF56D8253014570017B472 /* DisplayListDrawGlyphsRecorder.h */; settings = {ATTRIBUTES = (Private, ); }; };
1CCD81502231F83E0065FC2B /* WebCoreResourceHandleAsOperationQueueDelegate.mm in Sources */ = {isa = PBXBuildFile; fileRef = E152551416FD234F003D7ADB /* WebCoreResourceHandleAsOperationQueueDelegate.mm */; };
1CCDF5BE1990332400BCEBAD /* SVGToOTFFontConversion.h in Headers */ = {isa = PBXBuildFile; fileRef = 1CCDF5BC1990332400BCEBAD /* SVGToOTFFontConversion.h */; };
1CFAE3230A6D6A3F0032593D /* libobjc.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 1CFAE3220A6D6A3F0032593D /* libobjc.dylib */; };
@@ -6736,6 +6737,8 @@
1CAF347E0A6C405200ABE06E /* WebScriptObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebScriptObject.h; sourceTree = "<group>"; };
1CAF347F0A6C405200ABE06E /* WebScriptObject.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = WebScriptObject.mm; sourceTree = "<group>"; };
1CAF34800A6C405200ABE06E /* WebScriptObjectPrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebScriptObjectPrivate.h; sourceTree = "<group>"; };
+ 1CAF56D8253014570017B472 /* DisplayListDrawGlyphsRecorder.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DisplayListDrawGlyphsRecorder.h; sourceTree = "<group>"; };
+ 1CAF56DE2530245A0017B472 /* DisplayListDrawGlyphsRecorderCoreText.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = DisplayListDrawGlyphsRecorderCoreText.cpp; sourceTree = "<group>"; };
1CB5FE8822DEBC8B009440E2 /* WHLSLError.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WHLSLError.h; sourceTree = "<group>"; };
1CB69B3221DED40B006E846A /* WHLSLResolvableType.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WHLSLResolvableType.h; sourceTree = "<group>"; };
1CB69B3421DED63A006E846A /* WHLSLFloatLiteralType.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WHLSLFloatLiteralType.h; sourceTree = "<group>"; };
@@ -17610,6 +17613,8 @@
children = (
0FE5FBCA1C3DD51E0007A2CA /* DisplayList.cpp */,
0FE5FBCB1C3DD51E0007A2CA /* DisplayList.h */,
+ 1CAF56D8253014570017B472 /* DisplayListDrawGlyphsRecorder.h */,
+ 1CAF56DE2530245A0017B472 /* DisplayListDrawGlyphsRecorderCoreText.cpp */,
55C0A29523FE2CE000F2CB93 /* DisplayListDrawingContext.cpp */,
72EA09F923FCCC6A008504A5 /* DisplayListDrawingContext.h */,
72EA09F723FCCB3D008504A5 /* DisplayListImageBuffer.h */,
@@ -31434,6 +31439,7 @@
7EDAAFC919A2CCDC0034DFD1 /* DiskCacheMonitorCocoa.h in Headers */,
0F790F422517CE6E009BA034 /* DisplayLayerController.h in Headers */,
0FE5FBD31C3DD51E0007A2CA /* DisplayList.h in Headers */,
+ 1CAF56DB25301AC80017B472 /* DisplayListDrawGlyphsRecorder.h in Headers */,
55AD09402408964000DE4D2F /* DisplayListDrawingContext.h in Headers */,
55AD093E2408963500DE4D2F /* DisplayListImageBuffer.h in Headers */,
0FE5FBD51C3DD51E0007A2CA /* DisplayListItems.h in Headers */,
Modified: trunk/Source/WebCore/platform/FreeType.cmake (269210 => 269211)
--- trunk/Source/WebCore/platform/FreeType.cmake 2020-10-30 23:56:26 UTC (rev 269210)
+++ trunk/Source/WebCore/platform/FreeType.cmake 2020-10-31 00:01:02 UTC (rev 269211)
@@ -5,6 +5,8 @@
)
list(APPEND WebCore_SOURCES
+ platform/graphics/displaylists/DisplayListDrawGlyphsRecorderHarfBuzz.cpp
+
platform/graphics/freetype/FontCacheFreeType.cpp
platform/graphics/freetype/FontCustomPlatformDataFreeType.cpp
platform/graphics/freetype/FontPlatformDataFreeType.cpp
Modified: trunk/Source/WebCore/platform/graphics/cg/ImageBufferCGBackend.cpp (269210 => 269211)
--- trunk/Source/WebCore/platform/graphics/cg/ImageBufferCGBackend.cpp 2020-10-30 23:56:26 UTC (rev 269210)
+++ trunk/Source/WebCore/platform/graphics/cg/ImageBufferCGBackend.cpp 2020-10-31 00:01:02 UTC (rev 269211)
@@ -61,6 +61,7 @@
void ImageBufferCGBackend::setupContext()
{
+ // The initial CTM matches DisplayList::Recorder::clipToDrawingCommands()'s initial CTM.
context().scale(FloatSize(1, -1));
context().translate(0, -m_backendSize.height());
context().applyDeviceScaleFactor(m_resolutionScale);
Modified: trunk/Source/WebCore/platform/graphics/coretext/FontCascadeCoreText.cpp (269210 => 269211)
--- trunk/Source/WebCore/platform/graphics/coretext/FontCascadeCoreText.cpp 2020-10-30 23:56:26 UTC (rev 269210)
+++ trunk/Source/WebCore/platform/graphics/coretext/FontCascadeCoreText.cpp 2020-10-31 00:01:02 UTC (rev 269211)
@@ -41,6 +41,50 @@
namespace WebCore {
+static const AffineTransform& rotateLeftTransform()
+{
+ static AffineTransform result(0, -1, 1, 0, 0, 0);
+ return result;
+}
+
+AffineTransform computeOverallTextMatrix(const Font& font)
+{
+ auto& platformData = font.platformData();
+ AffineTransform result;
+ if (!platformData.isColorBitmapFont())
+ result = CTFontGetMatrix(platformData.ctFont());
+ result.setB(-result.b());
+ result.setD(-result.d());
+ if (platformData.syntheticOblique()) {
+ float obliqueSkew = tanf(deg2rad(FontCascade::syntheticObliqueAngle()));
+ if (platformData.orientation() == FontOrientation::Vertical) {
+ if (font.isTextOrientationFallback())
+ result = AffineTransform(1, obliqueSkew, 0, 1, 0, 0) * result;
+ else
+ result = AffineTransform(1, -obliqueSkew, 0, 1, 0, 0) * result;
+ } else
+ result = AffineTransform(1, 0, -obliqueSkew, 1, 0, 0) * result;
+ }
+
+ // We're emulating the behavior of CGContextSetTextPosition() by adding constant amounts to each glyph's position
+ // (see fillVectorWithHorizontalGlyphPositions() and fillVectorWithVerticalGlyphPositions()).
+ // CGContextSetTextPosition() has the side effect of clobbering the E and F fields of the text matrix,
+ // so we do that explicitly here.
+ result.setE(0);
+ result.setF(0);
+ return result;
+}
+
+AffineTransform computeVerticalTextMatrix(const Font& font, const AffineTransform& previousTextMatrix)
+{
+ ASSERT_UNUSED(font, font.platformData().orientation() == FontOrientation::Vertical);
+ // The translation here ("e" and "f" fields) are irrelevant, because
+ // this matrix is inverted in fillVectorWithVerticalGlyphPositions to place the glyphs in the CTM's coordinate system.
+ // All we're trying to do here is rotate the text matrix so glyphs appear visually upright.
+ // We have to include the previous text matrix because it includes things like synthetic oblique.
+ return rotateLeftTransform() * previousTextMatrix;
+}
+
#if !PLATFORM(WIN)
// Confusingly, even when CGFontRenderingGetFontSmoothingDisabled() returns true, CGContextSetShouldSmoothFonts() still impacts text
@@ -61,14 +105,16 @@
#endif
}
-static const AffineTransform& rotateLeftTransform()
-{
- static AffineTransform result(0, -1, 1, 0, 0, 0);
- return result;
-}
-
void fillVectorWithHorizontalGlyphPositions(Vector<CGPoint, 256>& positions, CGContextRef context, const CGSize* advances, unsigned count, const FloatPoint& point)
{
+ // The input positions are in the context's coordinate system, without the text matrix.
+ // However, the positions that CT/CG accept are in the text matrix's coordinate system.
+ // CGContextGetTextMatrix() gives us the matrix that maps from text's coordinate system to the context's (non-text) coordinate system.
+ // We need to figure out what to deliver CT, inside the text's coordinate system, such that it ends up coincident with the input in the context's coordinate system.
+ //
+ // CTM * text matrix * positions we need to deliver to CT = CTM * input positions
+ // Solving for the positions we need to deliver to CT, we get
+ // positions we need to deliver to CT = inverse(text matrix) * input positions
CGAffineTransform matrix = CGAffineTransformInvert(CGContextGetTextMatrix(context));
positions[0] = CGPointApplyAffineTransform(point, matrix);
for (unsigned i = 1; i < count; ++i) {
@@ -137,44 +183,6 @@
CGContextSetShouldSubpixelQuantizeFonts(cgContext, doSubpixelQuantization);
}
-AffineTransform computeOverallTextMatrix(const Font& font)
-{
- auto& platformData = font.platformData();
- AffineTransform result;
- if (!platformData.isColorBitmapFont())
- result = CTFontGetMatrix(platformData.font());
- result.setB(-result.b());
- result.setD(-result.d());
- if (platformData.syntheticOblique()) {
- float obliqueSkew = tanf(deg2rad(FontCascade::syntheticObliqueAngle()));
- if (platformData.orientation() == FontOrientation::Vertical) {
- if (font.isTextOrientationFallback())
- result = AffineTransform(1, obliqueSkew, 0, 1, 0, 0) * result;
- else
- result = AffineTransform(1, -obliqueSkew, 0, 1, 0, 0) * result;
- } else
- result = AffineTransform(1, 0, -obliqueSkew, 1, 0, 0) * result;
- }
-
- // We're emulating the behavior of CGContextSetTextPosition() by adding constant amounts to each glyph's position
- // (see fillVectorWithHorizontalGlyphPositions() and fillVectorWithVerticalGlyphPositions()).
- // CGContextSetTextPosition() has the side effect of clobbering the E and F fields of the text matrix,
- // so we do that explicitly here.
- result.setE(0);
- result.setF(0);
- return result;
-}
-
-AffineTransform computeVerticalTextMatrix(const Font& font, const AffineTransform& previousTextMatrix)
-{
- ASSERT_UNUSED(font, font.platformData().orientation() == FontOrientation::Vertical);
- // The translation here ("e" and "f" fields) are irrelevant, because
- // this matrix is inverted in fillVectorWithVerticalGlyphPositions to place the glyphs in the CTM's coordinate system.
- // All we're trying to do here is rotate the text matrix so glyphs appear visually upright.
- // We have to include the previous text matrix because it includes things like synthetic oblique.
- return rotateLeftTransform() * previousTextMatrix;
-}
-
void FontCascade::drawGlyphs(GraphicsContext& context, const Font& font, const GlyphBuffer& glyphBuffer, unsigned from, unsigned numGlyphs, const FloatPoint& anchorPoint, FontSmoothingMode smoothingMode)
{
const auto& platformData = font.platformData();
Added: trunk/Source/WebCore/platform/graphics/displaylists/DisplayListDrawGlyphsRecorder.h (0 => 269211)
--- trunk/Source/WebCore/platform/graphics/displaylists/DisplayListDrawGlyphsRecorder.h (rev 0)
+++ trunk/Source/WebCore/platform/graphics/displaylists/DisplayListDrawGlyphsRecorder.h 2020-10-31 00:01:02 UTC (rev 269211)
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2020 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include "AffineTransform.h"
+#include "Color.h"
+#include "Gradient.h"
+#include "GraphicsContext.h"
+#include "Pattern.h"
+#include "TextFlags.h"
+
+#if USE(CORE_TEXT)
+#include <CoreGraphics/CoreGraphics.h>
+#include <pal/spi/cg/CoreGraphicsSPI.h>
+#endif
+
+namespace WebCore {
+
+class FloatPoint;
+class Font;
+class GlyphBuffer;
+class GraphicsContext;
+
+namespace DisplayList {
+
+class Recorder;
+
+class DrawGlyphsRecorder {
+public:
+ explicit DrawGlyphsRecorder(Recorder&);
+
+ void drawGlyphs(const Font&, const GlyphBuffer&, unsigned from, unsigned numGlyphs, const FloatPoint& anchorPoint, FontSmoothingMode);
+
+#if USE(CORE_TEXT)
+ void recordBeginLayer(CGRenderingStateRef, CGGStateRef, CGRect);
+ void recordEndLayer(CGRenderingStateRef, CGGStateRef);
+ void recordDrawGlyphs(CGRenderingStateRef, CGGStateRef, const CGAffineTransform*, const CGGlyph[], const CGPoint positions[], size_t count);
+ void recordDrawImage(CGRenderingStateRef, CGGStateRef, CGRect, CGImageRef);
+#endif
+
+private:
+ GraphicsContext createInternalContext();
+
+ void populateInternalState(const GraphicsContextState&);
+ void populateInternalContext(const GraphicsContextState&);
+ void prepareInternalContext(const Font&, FontSmoothingMode);
+ void concludeInternalContext();
+
+ void updateFillColor(const Color&, Gradient* = nullptr, Pattern* = nullptr);
+ void updateStrokeColor(const Color&, Gradient* = nullptr, Pattern* = nullptr);
+ void updateCTM(const AffineTransform&);
+ enum class ShadowsIgnoreTransforms {
+ Unspecified,
+ Yes,
+ No
+ };
+ void updateShadow(const FloatSize& shadowOffset, float shadowBlur, const Color& shadowColor, ShadowsIgnoreTransforms);
+
+#if USE(CORE_TEXT)
+ void updateShadow(CGStyleRef);
+#endif
+
+ Recorder& m_owner;
+ GraphicsContext m_internalContext;
+ const Font* m_originalFont { nullptr };
+ FontSmoothingMode m_smoothingMode { FontSmoothingMode::AutoSmoothing };
+ AffineTransform m_originalTextMatrix;
+
+ struct State {
+ struct Style {
+ Color color;
+ RefPtr<Gradient> gradient;
+ RefPtr<Pattern> pattern;
+ };
+ Style fillStyle;
+ Style strokeStyle;
+
+ AffineTransform ctm;
+
+ struct ShadowState {
+ FloatSize offset;
+ float blur { 0 };
+ Color color;
+ bool ignoreTransforms { false };
+ };
+ ShadowState shadow;
+ };
+ State m_originalState;
+ State m_currentState;
+};
+
+}
+
+}
Property changes on: trunk/Source/WebCore/platform/graphics/displaylists/DisplayListDrawGlyphsRecorder.h
___________________________________________________________________
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Author Date Id Rev URL
\ No newline at end of property
Added: trunk/Source/WebCore/platform/graphics/displaylists/DisplayListDrawGlyphsRecorderCoreText.cpp (0 => 269211)
--- trunk/Source/WebCore/platform/graphics/displaylists/DisplayListDrawGlyphsRecorderCoreText.cpp (rev 0)
+++ trunk/Source/WebCore/platform/graphics/displaylists/DisplayListDrawGlyphsRecorderCoreText.cpp 2020-10-31 00:01:02 UTC (rev 269211)
@@ -0,0 +1,371 @@
+/*
+ * Copyright (C) 2020 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "DisplayListDrawGlyphsRecorder.h"
+
+#include "BitmapImage.h"
+#include "Color.h"
+#include "DisplayListItems.h"
+#include "DisplayListRecorder.h"
+#include "FloatPoint.h"
+#include "Font.h"
+#include "FontCascade.h"
+#include "GlyphBuffer.h"
+
+#include <CoreText/CoreText.h>
+#include <wtf/Vector.h>
+
+#if PLATFORM(WIN)
+#include <pal/spi/win/CoreTextSPIWin.h>
+#endif
+
+namespace WebCore {
+
+namespace DisplayList {
+
+static CGContextDelegateRef beginLayer(CGContextDelegateRef delegate, CGRenderingStateRef rstate, CGGStateRef gstate, CGRect rect, CFDictionaryRef, CGContextDelegateRef)
+{
+ DrawGlyphsRecorder& recorder = *static_cast<DrawGlyphsRecorder*>(CGContextDelegateGetInfo(delegate));
+ recorder.recordBeginLayer(rstate, gstate, rect);
+ return delegate;
+}
+
+static CGContextDelegateRef endLayer(CGContextDelegateRef delegate, CGRenderingStateRef rstate, CGGStateRef gstate)
+{
+ DrawGlyphsRecorder& recorder = *static_cast<DrawGlyphsRecorder*>(CGContextDelegateGetInfo(delegate));
+ recorder.recordEndLayer(rstate, gstate);
+ return delegate;
+}
+
+static CGError drawGlyphs(CGContextDelegateRef delegate, CGRenderingStateRef rstate, CGGStateRef gstate, const CGAffineTransform* tm, const CGGlyph glyphs[], const CGPoint positions[], size_t count)
+{
+ if (CGGStateGetAlpha(gstate) > 0) {
+ DrawGlyphsRecorder& recorder = *static_cast<DrawGlyphsRecorder*>(CGContextDelegateGetInfo(delegate));
+ recorder.recordDrawGlyphs(rstate, gstate, tm, glyphs, positions, count);
+ }
+ return kCGErrorSuccess;
+}
+
+static CGError drawImage(CGContextDelegateRef delegate, CGRenderingStateRef rstate, CGGStateRef gstate, CGRect rect, CGImageRef image)
+{
+ DrawGlyphsRecorder& recorder = *static_cast<DrawGlyphsRecorder*>(CGContextDelegateGetInfo(delegate));
+ recorder.recordDrawImage(rstate, gstate, rect, image);
+ return kCGErrorSuccess;
+}
+
+GraphicsContext DrawGlyphsRecorder::createInternalContext()
+{
+ auto contextDelegate = adoptCF(CGContextDelegateCreate(this));
+ CGContextDelegateSetCallback(contextDelegate.get(), deBeginLayer, reinterpret_cast<CGContextDelegateCallback>(&beginLayer));
+ CGContextDelegateSetCallback(contextDelegate.get(), deEndLayer, reinterpret_cast<CGContextDelegateCallback>(&endLayer));
+ CGContextDelegateSetCallback(contextDelegate.get(), deDrawGlyphs, reinterpret_cast<CGContextDelegateCallback>(&WebCore::DisplayList::drawGlyphs));
+ CGContextDelegateSetCallback(contextDelegate.get(), deDrawImage, reinterpret_cast<CGContextDelegateCallback>(&drawImage));
+ auto context = adoptCF(CGContextCreateWithDelegate(contextDelegate.get(), kCGContextTypeUnknown, nullptr, nullptr));
+ return GraphicsContext(context.get());
+}
+
+DrawGlyphsRecorder::DrawGlyphsRecorder(Recorder& owner)
+ : m_owner(owner)
+ , m_internalContext(createInternalContext())
+{
+}
+
+void DrawGlyphsRecorder::populateInternalState(const GraphicsContextState& contextState)
+{
+ m_originalState.fillStyle.color = contextState.fillColor;
+ m_originalState.fillStyle.gradient = contextState.fillGradient;
+ m_originalState.fillStyle.pattern = contextState.fillPattern;
+
+ m_originalState.strokeStyle.color = contextState.strokeColor;
+ m_originalState.strokeStyle.gradient = contextState.strokeGradient;
+ m_originalState.strokeStyle.pattern = contextState.strokePattern;
+
+ m_originalState.ctm = m_owner.currentState().ctm; // FIXME: Deal with base CTM.
+
+ m_originalState.shadow.offset = contextState.shadowOffset;
+ m_originalState.shadow.blur = contextState.shadowBlur;
+ m_originalState.shadow.color = contextState.shadowColor;
+ m_originalState.shadow.ignoreTransforms = contextState.shadowsIgnoreTransforms;
+
+ m_currentState = m_originalState;
+}
+
+void DrawGlyphsRecorder::populateInternalContext(const GraphicsContextState& contextState)
+{
+ if (m_originalState.fillStyle.color.isValid())
+ m_internalContext.setFillColor(m_originalState.fillStyle.color);
+ else if (m_originalState.fillStyle.gradient)
+ m_internalContext.setFillGradient(*m_originalState.fillStyle.gradient);
+ else {
+ ASSERT(m_originalState.fillStyle.pattern);
+ if (m_originalState.fillStyle.pattern)
+ m_internalContext.setFillPattern(*m_originalState.fillStyle.pattern);
+ }
+
+ if (m_originalState.strokeStyle.color.isValid())
+ m_internalContext.setStrokeColor(m_originalState.strokeStyle.color);
+ else if (m_originalState.strokeStyle.gradient)
+ m_internalContext.setStrokeGradient(*m_originalState.strokeStyle.gradient);
+ else {
+ ASSERT(m_originalState.strokeStyle.pattern);
+ if (m_originalState.strokeStyle.pattern)
+ m_internalContext.setStrokePattern(*m_originalState.strokeStyle.pattern);
+ }
+
+ m_internalContext.setCTM(m_originalState.ctm);
+
+ m_internalContext.setShadowsIgnoreTransforms(m_originalState.shadow.ignoreTransforms);
+ if (contextState.shadowsUseLegacyRadius)
+ m_internalContext.setLegacyShadow(m_originalState.shadow.offset, m_originalState.shadow.blur, m_originalState.shadow.color);
+ else
+ m_internalContext.setShadow(m_originalState.shadow.offset, m_originalState.shadow.blur, m_originalState.shadow.color);
+
+ m_internalContext.setTextDrawingMode(contextState.textDrawingMode);
+}
+
+void DrawGlyphsRecorder::prepareInternalContext(const Font& font, FontSmoothingMode smoothingMode)
+{
+ ASSERT(CGAffineTransformIsIdentity(CTFontGetMatrix(font.platformData().ctFont())));
+
+ m_originalFont = &font;
+ m_smoothingMode = smoothingMode;
+
+ m_originalTextMatrix = computeOverallTextMatrix(font);
+ if (font.platformData().orientation() == FontOrientation::Vertical)
+ m_originalTextMatrix = computeVerticalTextMatrix(font, m_originalTextMatrix);
+
+ auto& contextState = m_owner.currentState().stateChange.m_state;
+ populateInternalState(contextState);
+ populateInternalContext(contextState);
+}
+
+void DrawGlyphsRecorder::concludeInternalContext()
+{
+ updateCTM(m_originalState.ctm);
+ updateFillColor(m_originalState.fillStyle.color, m_originalState.fillStyle.gradient.get(), m_originalState.fillStyle.pattern.get());
+ updateStrokeColor(m_originalState.strokeStyle.color, m_originalState.strokeStyle.gradient.get(), m_originalState.strokeStyle.pattern.get());
+ updateShadow(m_originalState.shadow.offset, m_originalState.shadow.blur, m_originalState.shadow.color, m_originalState.shadow.ignoreTransforms ? ShadowsIgnoreTransforms::Yes : ShadowsIgnoreTransforms::No);
+}
+
+void DrawGlyphsRecorder::updateFillColor(const Color& newColor, Gradient* newGradient, Pattern* newPattern)
+{
+ // This check looks wrong but it actually isn't, for our limited use.
+ // CT will only ever set this to a solid color, which this is the correct check for.
+ // In concludeInternalContext() we set it back to what it was originally, which this check works correctly for too.
+ if (newColor == m_currentState.fillStyle.color)
+ return;
+
+ GraphicsContextState newState;
+ newState.fillColor = newColor;
+ if (newGradient)
+ newState.fillGradient = newGradient;
+ if (newPattern)
+ newState.fillPattern = newPattern;
+ m_owner.updateState(newState, { GraphicsContextState::FillColorChange });
+ m_currentState.fillStyle.color = newColor;
+}
+
+void DrawGlyphsRecorder::updateStrokeColor(const Color& newColor, Gradient* newGradient, Pattern* newPattern)
+{
+ // This check looks wrong but it actually isn't, for our limited use.
+ // CT will only ever set this to a solid color, which this is the correct check for.
+ // In concludeInternalContext() we set it back to what it was originally, which this check works correctly for too.
+ if (newColor == m_currentState.strokeStyle.color)
+ return;
+
+ GraphicsContextState newState;
+ newState.strokeColor = newColor;
+ if (newGradient)
+ newState.strokeGradient = newGradient;
+ if (newPattern)
+ newState.strokePattern = newPattern;
+ m_owner.updateState(newState, { GraphicsContextState::StrokeColorChange });
+ m_currentState.strokeStyle.color = newColor;
+}
+
+void DrawGlyphsRecorder::updateCTM(const AffineTransform& ctm)
+{
+ if (ctm == m_currentState.ctm)
+ return;
+
+ m_owner.setCTM(ctm);
+ m_currentState.ctm = ctm;
+}
+
+static bool shadowIsCleared(const FloatSize& shadowOffset, float shadowBlur)
+{
+ return shadowOffset == FloatSize() && !shadowBlur;
+}
+
+void DrawGlyphsRecorder::updateShadow(const FloatSize& shadowOffset, float shadowBlur, const Color& shadowColor, ShadowsIgnoreTransforms shadowsIgnoreTransforms)
+{
+ // We don't need to consider shadowsIgnoreTransforms if nobody has any shadows.
+ if (shadowIsCleared(shadowOffset, shadowBlur) && shadowIsCleared(m_currentState.shadow.offset, m_currentState.shadow.blur))
+ return;
+
+ GraphicsContextState newState;
+ GraphicsContextState::StateChangeFlags stateChangeFlags;
+
+ if (shadowOffset != m_currentState.shadow.offset || shadowBlur != m_currentState.shadow.blur || shadowColor != m_currentState.shadow.color) {
+ newState.shadowOffset = shadowOffset;
+ newState.shadowBlur = shadowBlur;
+ newState.shadowColor = shadowColor;
+ stateChangeFlags.add(GraphicsContextState::ShadowChange);
+ }
+ if (shadowsIgnoreTransforms != ShadowsIgnoreTransforms::Unspecified && (shadowsIgnoreTransforms == ShadowsIgnoreTransforms::Yes) != m_currentState.shadow.ignoreTransforms) {
+ newState.shadowsIgnoreTransforms = (shadowsIgnoreTransforms == ShadowsIgnoreTransforms::Yes);
+ stateChangeFlags.add(GraphicsContextState::ShadowsIgnoreTransformsChange);
+ }
+ if (stateChangeFlags.isEmpty())
+ return;
+ m_owner.updateState(newState, stateChangeFlags);
+
+ m_currentState.shadow.offset = shadowOffset;
+ m_currentState.shadow.blur = shadowBlur;
+ m_currentState.shadow.color = shadowColor;
+ m_currentState.shadow.ignoreTransforms = (shadowsIgnoreTransforms == ShadowsIgnoreTransforms::Yes);
+}
+
+void DrawGlyphsRecorder::updateShadow(CGStyleRef style)
+{
+ if (CGStyleGetType(style) != kCGStyleShadow) {
+ // FIXME: Support more kinds of CGStyles.
+ updateShadow({0, 0}, 0, Color(), ShadowsIgnoreTransforms::Unspecified);
+ return;
+ }
+
+ const auto& shadowStyle = *static_cast<const CGShadowStyle*>(CGStyleGetData(style));
+ auto rad = deg2rad(shadowStyle.azimuth - 180);
+ auto shadowOffset = FloatSize(std::cos(rad), std::sin(rad)) * shadowStyle.height;
+ updateShadow(shadowOffset, shadowStyle.radius, CGStyleGetColor(style), ShadowsIgnoreTransforms::Yes);
+}
+
+void DrawGlyphsRecorder::recordBeginLayer(CGRenderingStateRef, CGGStateRef gstate, CGRect)
+{
+ updateCTM(*CGGStateGetCTM(gstate));
+ auto alpha = CGGStateGetAlpha(gstate);
+ m_owner.beginTransparencyLayer(alpha);
+}
+
+void DrawGlyphsRecorder::recordEndLayer(CGRenderingStateRef, CGGStateRef gstate)
+{
+ updateCTM(*CGGStateGetCTM(gstate));
+ m_owner.endTransparencyLayer();
+}
+
+static Vector<CGSize> computeAdvancesFromPositions(const CGPoint positions[], size_t count, const CGAffineTransform& textMatrix)
+{
+ Vector<CGSize> result;
+ for (size_t i = 0; i < count - 1; ++i) {
+ auto nextPosition = positions[i + 1];
+ auto currentPosition = positions[i];
+ auto advance = CGSizeMake(nextPosition.x - currentPosition.x, nextPosition.y - currentPosition.y);
+ result.append(CGSizeApplyAffineTransform(advance, textMatrix));
+ }
+ result.constructAndAppend(CGSizeMake(0, 0));
+ return result;
+}
+
+void DrawGlyphsRecorder::recordDrawGlyphs(CGRenderingStateRef, CGGStateRef gstate, const CGAffineTransform*, const CGGlyph glyphs[], const CGPoint positions[], size_t count)
+{
+ if (!count)
+ return;
+
+ CGFontRef usedFont = CGGStateGetFont(gstate);
+ if (usedFont != adoptCF(CTFontCopyGraphicsFont(m_originalFont->platformData().ctFont(), nullptr)).get())
+ return;
+
+#if ASSERT_ENABLED
+ auto textPosition = CGContextGetTextPosition(m_internalContext.platformContext());
+ ASSERT(!textPosition.x);
+ ASSERT(!textPosition.y);
+#endif
+
+ updateCTM(*CGGStateGetCTM(gstate));
+
+ // We want the replayer's CTM and text matrix to match the current CTM and text matrix.
+ // The current text matrix is a concatenation of whatever WebKit sets it to and whatever
+ // Core Text appends to it. So, we have
+ // CTM * m_originalTextMatrix * Core Text's text matrix.
+ // However, CGContextGetTextMatrix() just tells us what the whole text matrix is, so
+ // m_originalTextMatrix * Core Text's text matrix = currentTextMatrix.
+ // The only way we can emulate Core Text's text matrix is by modifying the CTM here.
+ // So, if we do that, the GPU process will have
+ // CTM * X * m_originalTextMatrix
+ // If you set these two equal to each other, and solve for X, you get
+ // CTM * currentTextMatrix = CTM * X * m_originalTextMatrix
+ // currentTextMatrix * inverse(m_originalTextMatrix) = X
+ AffineTransform currentTextMatrix = CGContextGetTextMatrix(m_internalContext.platformContext());
+ AffineTransform ctmFixup;
+ if (auto invertedOriginalTextMatrix = m_originalTextMatrix.inverse())
+ ctmFixup = currentTextMatrix * invertedOriginalTextMatrix.value();
+ AffineTransform inverseCTMFixup;
+ if (auto inverse = ctmFixup.inverse())
+ inverseCTMFixup = inverse.value();
+ else
+ ctmFixup = AffineTransform();
+ m_owner.concatCTM(ctmFixup);
+
+ updateFillColor(CGGStateGetFillColor(gstate));
+ updateStrokeColor(CGGStateGetStrokeColor(gstate));
+ updateShadow(CGGStateGetStyle(gstate));
+
+ m_owner.appendItemAndUpdateExtent(DrawGlyphs::create(*m_originalFont, glyphs, computeAdvancesFromPositions(positions, count, currentTextMatrix).data(), count, currentTextMatrix.mapPoint(positions[0]), m_smoothingMode));
+
+ m_owner.concatCTM(inverseCTMFixup);
+}
+
+void DrawGlyphsRecorder::recordDrawImage(CGRenderingStateRef, CGGStateRef gstate, CGRect rect, CGImageRef cgImage)
+{
+ updateCTM(*CGGStateGetCTM(gstate));
+ updateShadow(CGGStateGetStyle(gstate));
+
+ // Core Graphics assumes a "y up" coordinate system, but in WebKit, we use a "y-down" coordinate system.
+ // This means that WebKit's drawing routines (GraphicsContext::drawImage()) intentionally draw images upside-down from Core Graphics's point of view.
+ // (There's a y-flip inside the implementation of GraphicsContext::drawImage().)
+ // The rect has the right bounds, but we need to transform from CG's coordinate system to WebKit's by performing our own y-flip so images are drawn the right-side-up.
+ // We do this at the boundary between the two APIs, which is right here.
+ m_owner.translate(0, rect.size.height + 2 * rect.origin.y);
+ m_owner.scale(FloatSize(1, -1));
+
+ auto image = BitmapImage::create(cgImage);
+ m_owner.appendItemAndUpdateExtent(DrawImage::create(image, rect, {{ }, image->size()}, { ImageOrientation::OriginTopLeft }));
+
+ // Undo the above y-flip to restore the context.
+ m_owner.scale(FloatSize(1, -1));
+ m_owner.translate(0, -(rect.size.height + 2 * rect.origin.y));
+}
+
+void DrawGlyphsRecorder::drawGlyphs(const Font& font, const GlyphBuffer& glyphBuffer, unsigned from, unsigned numGlyphs, const FloatPoint& startPoint, FontSmoothingMode smoothingMode)
+{
+ prepareInternalContext(font, smoothingMode);
+ FontCascade::drawGlyphs(m_internalContext, font, glyphBuffer, from, numGlyphs, startPoint, smoothingMode);
+ concludeInternalContext();
+}
+
+} // namespace DisplayList
+
+} // namespace WebCore
Property changes on: trunk/Source/WebCore/platform/graphics/displaylists/DisplayListDrawGlyphsRecorderCoreText.cpp
___________________________________________________________________
Added: svn:eol-style
+native
\ No newline at end of property
Added: trunk/Source/WebCore/platform/graphics/displaylists/DisplayListDrawGlyphsRecorderHarfBuzz.cpp (0 => 269211)
--- trunk/Source/WebCore/platform/graphics/displaylists/DisplayListDrawGlyphsRecorderHarfBuzz.cpp (rev 0)
+++ trunk/Source/WebCore/platform/graphics/displaylists/DisplayListDrawGlyphsRecorderHarfBuzz.cpp 2020-10-31 00:01:02 UTC (rev 269211)
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2020 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "DisplayListDrawGlyphsRecorder.h"
+
+#include "DisplayListItems.h"
+#include "DisplayListRecorder.h"
+#include "FloatPoint.h"
+#include "Font.h"
+#include "GlyphBuffer.h"
+
+namespace WebCore {
+
+namespace DisplayList {
+
+DrawGlyphsRecorder::DrawGlyphsRecorder(Recorder& owner)
+ : m_owner(owner)
+{
+}
+
+void DrawGlyphsRecorder::drawGlyphs(const Font& font, const GlyphBuffer& glyphBuffer, unsigned from, unsigned numGlyphs, const FloatPoint& startPoint, FontSmoothingMode smoothingMode)
+{
+ m_owner.appendItemAndUpdateExtent(DrawGlyphs::create(font, glyphBuffer.glyphs(from), glyphBuffer.advances(from), numGlyphs, startPoint, smoothingMode));
+}
+
+} // namespace DisplayList
+
+} // namespace WebCore
Property changes on: trunk/Source/WebCore/platform/graphics/displaylists/DisplayListDrawGlyphsRecorderHarfBuzz.cpp
___________________________________________________________________
Added: svn:eol-style
+native
\ No newline at end of property
Added: trunk/Source/WebCore/platform/graphics/displaylists/DisplayListDrawGlyphsRecorderWin.cpp (0 => 269211)
--- trunk/Source/WebCore/platform/graphics/displaylists/DisplayListDrawGlyphsRecorderWin.cpp (rev 0)
+++ trunk/Source/WebCore/platform/graphics/displaylists/DisplayListDrawGlyphsRecorderWin.cpp 2020-10-31 00:01:02 UTC (rev 269211)
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2020 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "DisplayListDrawGlyphsRecorder.h"
+
+#include "DisplayListItems.h"
+#include "DisplayListRecorder.h"
+#include "FloatPoint.h"
+#include "Font.h"
+#include "GlyphBuffer.h"
+
+namespace WebCore {
+
+namespace DisplayList {
+
+DrawGlyphsRecorder::DrawGlyphsRecorder(Recorder& owner)
+ : m_owner(owner)
+{
+}
+
+void DrawGlyphsRecorder::drawGlyphs(const Font& font, const GlyphBuffer& glyphBuffer, unsigned from, unsigned numGlyphs, const FloatPoint& startPoint, FontSmoothingMode smoothingMode)
+{
+ m_owner.appendItemAndUpdateExtent(DrawGlyphs::create(font, glyphBuffer.glyphs(from), glyphBuffer.advances(from), numGlyphs, startPoint, smoothingMode));
+}
+
+} // namespace DisplayList
+
+} // namespace WebCore
Property changes on: trunk/Source/WebCore/platform/graphics/displaylists/DisplayListDrawGlyphsRecorderWin.cpp
___________________________________________________________________
Added: svn:eol-style
+native
\ No newline at end of property
Modified: trunk/Source/WebCore/platform/graphics/displaylists/DisplayListRecorder.cpp (269210 => 269211)
--- trunk/Source/WebCore/platform/graphics/displaylists/DisplayListRecorder.cpp 2020-10-30 23:56:26 UTC (rev 269210)
+++ trunk/Source/WebCore/platform/graphics/displaylists/DisplayListRecorder.cpp 2020-10-31 00:01:02 UTC (rev 269211)
@@ -42,6 +42,7 @@
: GraphicsContextImpl(context, initialClip, AffineTransform())
, m_displayList(displayList)
, m_delegate(delegate)
+ , m_drawGlyphsRecorder(*this)
{
LOG_WITH_STREAM(DisplayLists, stream << "\nRecording with clip " << initialClip);
m_stateStack.append({ state, initialCTM, initialClip });
@@ -163,7 +164,7 @@
void Recorder::drawGlyphs(const Font& font, const GlyphBuffer& glyphBuffer, unsigned from, unsigned numGlyphs, const FloatPoint& startPoint, FontSmoothingMode smoothingMode)
{
- appendItemAndUpdateExtent(DrawGlyphs::create(font, glyphBuffer.glyphs(from), glyphBuffer.advances(from), numGlyphs, startPoint, smoothingMode));
+ m_drawGlyphsRecorder.drawGlyphs(font, glyphBuffer, from, numGlyphs, startPoint, smoothingMode);
}
ImageDrawResult Recorder::drawImage(Image& image, const FloatRect& destination, const FloatRect& source, const ImagePaintingOptions& imagePaintingOptions)
@@ -243,6 +244,9 @@
void Recorder::concatCTM(const AffineTransform& transform)
{
+ if (transform.isIdentity())
+ return;
+
currentState().concatCTM(transform);
appendItem(ConcatenateCTM::create(transform));
}
@@ -428,7 +432,17 @@
void Recorder::clipToDrawingCommands(const FloatRect& destination, ColorSpace colorSpace, Function<void(GraphicsContext&)>&& drawingFunction)
{
- auto recordingContext = makeUnique<DrawingContext>(destination.size());
+ // The initial CTM matches ImageBuffer's initial CTM.
+ AffineTransform transform = getCTM(GraphicsContext::DefinitelyIncludeDeviceScale);
+ FloatSize scaleFactor(transform.xScale(), transform.yScale());
+ auto scaledSize = expandedIntSize(destination.size() * scaleFactor);
+
+ AffineTransform initialCTM;
+ initialCTM.scale(1, -1);
+ initialCTM.translate(0, -scaledSize.height());
+ initialCTM.scale(scaledSize / destination.size());
+
+ auto recordingContext = makeUnique<DrawingContext>(destination.size(), initialCTM);
drawingFunction(recordingContext->context());
appendItem(ClipToDrawingCommands::create(destination, colorSpace, recordingContext->takeDisplayList()));
}
Modified: trunk/Source/WebCore/platform/graphics/displaylists/DisplayListRecorder.h (269210 => 269211)
--- trunk/Source/WebCore/platform/graphics/displaylists/DisplayListRecorder.h 2020-10-30 23:56:26 UTC (rev 269210)
+++ trunk/Source/WebCore/platform/graphics/displaylists/DisplayListRecorder.h 2020-10-31 00:01:02 UTC (rev 269211)
@@ -26,6 +26,7 @@
#pragma once
#include "DisplayList.h"
+#include "DisplayListDrawGlyphsRecorder.h"
#include "GraphicsContextImpl.h"
#include "Image.h" // For Image::TileRule.
#include "TextFlags.h"
@@ -61,8 +62,6 @@
size_t itemCount() const { return m_displayList.itemCount(); }
- void appendItemAndUpdateExtent(Ref<DrawingItem>&&);
-
class Delegate {
public:
virtual ~Delegate() { }
@@ -72,6 +71,7 @@
};
private:
+ friend class DrawGlyphsRecorder;
bool hasPlatformContext() const override { return false; }
PlatformGraphicsContext* platformContext() const override { return nullptr; }
@@ -151,6 +151,7 @@
void appendItem(Ref<Item>&&);
void willAppendItem(const Item&);
void didAppendItem(const Item&);
+ void appendItemAndUpdateExtent(Ref<DrawingItem>&&);
void appendStateChangeItem(const GraphicsContextStateChange&, GraphicsContextState::StateChangeFlags);
@@ -195,6 +196,8 @@
Delegate* m_delegate;
Vector<ContextState, 32> m_stateStack;
+
+ DrawGlyphsRecorder m_drawGlyphsRecorder;
};
}