diff --git a/src/Alexandrie-Cairo/AeCairoExternalArray.class.st b/src/Alexandrie-Cairo/AeCairoExternalArray.class.st index 23272c8..05a5585 100644 --- a/src/Alexandrie-Cairo/AeCairoExternalArray.class.st +++ b/src/Alexandrie-Cairo/AeCairoExternalArray.class.st @@ -24,9 +24,16 @@ AeCairoExternalArray class >> fromHandle: aHandle size: aNumber [ { #category : #'class initialization' } AeCairoExternalArray class >> initialize [ + self isAbstract ifTrue: [ ^self ]. resolvedType := self resolveType: self type ] +{ #category : #testing } +AeCairoExternalArray class >> isAbstract [ + + ^ self == AeCairoExternalArray +] + { #category : #'instance creation' } AeCairoExternalArray class >> newFrom: anArrayedCollection [ diff --git a/src/Alexandrie-Cairo/AeCairoGlyph.class.st b/src/Alexandrie-Cairo/AeCairoGlyph.class.st index 5784c41..730c167 100644 --- a/src/Alexandrie-Cairo/AeCairoGlyph.class.st +++ b/src/Alexandrie-Cairo/AeCairoGlyph.class.st @@ -58,9 +58,9 @@ AeCairoGlyph >> printShortOn: aStream [ aStream nextPutAll: '('; - print: self position; - nextPutAll: ' -> '; print: self index; + nextPutAll: ': '; + print: self position; nextPut: $) ] diff --git a/src/Alexandrie-Cairo/AeCairoTextCluster.class.st b/src/Alexandrie-Cairo/AeCairoTextCluster.class.st index 6343c69..19f6fc7 100644 --- a/src/Alexandrie-Cairo/AeCairoTextCluster.class.st +++ b/src/Alexandrie-Cairo/AeCairoTextCluster.class.st @@ -52,3 +52,21 @@ AeCairoTextCluster >> glyphCount: anObject [ "This method was automatically generated" handle signedLongAt: OFFSET_GLYPHCOUNT put: anObject ] + +{ #category : #printing } +AeCairoTextCluster >> printOn: aStream [ + + super printOn: aStream. + self printShortOn: aStream +] + +{ #category : #printing } +AeCairoTextCluster >> printShortOn: aStream [ + + aStream + nextPut: $(; + print: self byteCount; + nextPutAll: ' '; + print: self glyphCount; + nextPut: $) +] diff --git a/src/Alexandrie-Cairo/AeCairoTextToGlyphShaping.class.st b/src/Alexandrie-Cairo/AeCairoTextToGlyphShaping.class.st index ee9f6d6..b4f1d4f 100644 --- a/src/Alexandrie-Cairo/AeCairoTextToGlyphShaping.class.st +++ b/src/Alexandrie-Cairo/AeCairoTextToGlyphShaping.class.st @@ -1,6 +1,8 @@ Class { #name : #AeCairoTextToGlyphShaping, #superclass : #Object, + #traits : 'AeTCairoLibrary', + #classTraits : 'AeTCairoLibrary classTrait', #instVars : [ 'scaledFont', 'x', @@ -17,6 +19,45 @@ Class { #category : #'Alexandrie-Cairo-Text' } +{ #category : #examples } +AeCairoTextToGlyphShaping class >> exampleShapeAndDraw [ + + | fontSize string surfaceSize aSurface aContext aFTLibrary aFTFace aScaledFont aShaping aStatus | + fontSize := 12. + "Get Lorem Ipsum without last cr character" + string := (String loremIpsum: 28) allButLast. + surfaceSize := 150 @ (fontSize*1.3). + aSurface := AeCairoImageSurface + extent: surfaceSize + format: AeCairoSurfaceFormat argb32. + aContext := aSurface newContext. + + "Set up scaled font in the context" + aFTLibrary := AeFTLibrary newInitialized. + aFTFace := AeSourceSansPro_Regular firstFaceUsing: aFTLibrary. + aContext + fontFace: (AeCairoFreetypeFontFace newForFace: aFTFace); + fontSize: fontSize. + aScaledFont := aContext scaledFont. + + aShaping := AeCairoTextToGlyphShaping new. + aShaping string: string. + aShaping scaledFont: aScaledFont. + aStatus := aShaping convertTextToGlyphs. + aStatus ensureIsSuccess. +" aShaping newGlyphArray. + aShaping newClusterArray." + + aContext + translateByX: 5 y: fontSize; + sourceColor: Color blue; + scaledFont: aScaledFont. + + aShaping showTextGlyphsOn: aContext. + + ^ aSurface inspect +] + { #category : #private } AeCairoTextToGlyphShaping >> convertTextToGlyphs [ "Convert UTF-8 text to an array of glyphs. Return `CAIRO_STATUS_SUCCESS` upon success, or an error status if the input values are wrong or if conversion failed. @@ -49,9 +90,53 @@ AeCairoTextToGlyphShaping >> initialize [ x := y := 0.0. - clusters := nil. - clusterCount := nil. - clusterFlags := nil. + glyphs := ExternalAddress new. + glyphCount := FFIInt32 newBuffer. + + clusters := ExternalAddress new. + clusterCount := FFIInt32 newBuffer. + clusterFlags := FFIInt32 newBuffer. +] + +{ #category : #API } +AeCairoTextToGlyphShaping >> newClusterArray [ + "Precondition: convertTextToGlyphs" + + | clusterArray | + clusterCount := clusterCount signedLongAt: 1. + clusterArray := clusterCount isZero + ifTrue: [ + AeCairoTextClusterArray unownedNewOf: 0 ] + ifFalse: [ + AeCairoTextClusterArray + fromHandle: clusters + size: clusterCount ]. + + "In both cases we must take care of freeing the array." + clusterArray autoRelease. + + ^ clusterArray +] + +{ #category : #API } +AeCairoTextToGlyphShaping >> newGlyphArray [ + "Precondition: convertTextToGlyphs" + + | glyphArray | + "Cairo returns NULL pointer when no glyphs, so needs special treatment." + glyphCount := glyphCount signedLongAt: 1. + glyphArray := glyphCount isZero + ifTrue: [ + AeCairoGlyphArray unownedNewOf: 0 ] + ifFalse: [ + AeCairoGlyphArray + fromHandle: glyphs + size: glyphCount ]. + + "In both cases we must take care of freeing the array." + glyphArray autoRelease. + + ^ glyphArray ] { #category : #API } @@ -67,11 +152,11 @@ AeCairoTextToGlyphShaping >> newGlyphArrayByConvertingText [ ifTrue: [ AeCairoGlyphArray unownedNewOf: 0 ] ifFalse: [ - AeCairoOpaqueGlyphArray + AeCairoGlyphArray fromHandle: glyphs size: glyphCount ]. - "In both cases we must to take care of freeing the array." + "In both cases we must take care of freeing the array." glyphArray autoRelease. ^ glyphArray @@ -100,9 +185,9 @@ AeCairoTextToGlyphShaping >> showTextGlyphsOn: cairoContext [ int utf8ByteCount, void *glyphs, int glyphCount, - const cairo_text_cluster_t *clusters, + void *clusters, int clusterCount, - cairo_text_cluster_flags_t clusterFlags + int clusterFlags ) ) ]