Skip to content

Commit

Permalink
Fix stream handling (#325)
Browse files Browse the repository at this point in the history
Passing immutable object as `Any` to C code does not guarantee pointer identity
with the original object/object stored in parent object.

Fix #323
  • Loading branch information
yuyichao authored Jul 5, 2020
1 parent a591b52 commit 73d7f71
Showing 1 changed file with 47 additions and 19 deletions.
66 changes: 47 additions & 19 deletions src/Cairo.jl
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,11 @@ mutable struct CairoSurfaceIOStream{T<:Union{UInt32,RGB24,ARGB32}} <: CairoSurfa
self
end
end
function get_stream_ptr(surf::T) where {T<:CairoSurfaceIOStream}
GC.@preserve surf begin
return unsafe_load(Ptr{Ptr{Nothing}}(pointer_from_objref(surf) + fieldoffset(T, 4)))
end
end


CairoSurface(ptr, w, h) = CairoSurface{UInt32}(ptr, w, h)
Expand Down Expand Up @@ -308,9 +313,13 @@ format(surf::CairoSurface{T}) where {T<:Union{RGB24,ARGB32}} = T

function CairoPDFSurface(stream::T, w::Real, h::Real) where {T<:IO}
callback = get_stream_callback(T)
ptr = ccall((:cairo_pdf_surface_create_for_stream,libcairo), Ptr{Nothing},
(Ptr{Nothing}, Any, Float64, Float64), callback, stream, w, h)
CairoSurface(ptr, w, h, stream)
surf = CairoSurface(C_NULL, w, h, stream)
GC.@preserve surf begin
surf.ptr = ccall((:cairo_pdf_surface_create_for_stream,libcairo), Ptr{Nothing},
(Ptr{Nothing}, Ptr{Nothing}, Float64, Float64), callback,
get_stream_ptr(surf), w, h)
end
return surf
end

function CairoPDFSurface(filename::AbstractString, w_pts::Real, h_pts::Real)
Expand All @@ -323,11 +332,15 @@ end

function CairoEPSSurface(stream::T, w::Real, h::Real) where {T<:IO}
callback = get_stream_callback(T)
ptr = ccall((:cairo_ps_surface_create_for_stream,libcairo), Ptr{Nothing},
(Ptr{Nothing}, Any, Float64, Float64), callback, stream, w, h)
ccall((:cairo_ps_surface_set_eps,libcairo), Nothing,
(Ptr{Nothing},Int32), ptr, 1)
CairoSurface(ptr, w, h, stream)
surf = CairoSurface(C_NULL, w, h, stream)
GC.@preserve surf begin
surf.ptr = ccall((:cairo_ps_surface_create_for_stream,libcairo), Ptr{Nothing},
(Ptr{Nothing}, Ptr{Nothing}, Float64, Float64),
callback, get_stream_ptr(surf), w, h)
ccall((:cairo_ps_surface_set_eps,libcairo), Nothing,
(Ptr{Nothing},Int32), surf.ptr, 1)
end
return surf
end

function CairoEPSSurface(filename::AbstractString, w_pts::Real, h_pts::Real)
Expand All @@ -342,11 +355,15 @@ end

function CairoPSSurface(stream::T, w::Real, h::Real) where {T<:IO}
callback = get_stream_callback(T)
ptr = ccall((:cairo_ps_surface_create_for_stream,libcairo), Ptr{Nothing},
(Ptr{Nothing}, Any, Float64, Float64), callback, stream, w, h)
ccall((:cairo_ps_surface_set_eps,libcairo), Nothing,
(Ptr{Nothing},Int32), ptr, 0)
CairoSurface(ptr, w, h, stream)
surf = CairoSurface(C_NULL, w, h, stream)
GC.@preserve surf begin
surf.ptr = ccall((:cairo_ps_surface_create_for_stream,libcairo), Ptr{Nothing},
(Ptr{Nothing}, Ptr{Nothing}, Float64, Float64),
callback, get_stream_ptr(surf), w, h)
ccall((:cairo_ps_surface_set_eps,libcairo), Nothing,
(Ptr{Nothing},Int32), surf.ptr, 0)
end
return surf
end

function CairoPSSurface(filename::AbstractString, w_pts::Real, h_pts::Real)
Expand Down Expand Up @@ -390,9 +407,13 @@ end

function CairoSVGSurface(stream::T, w::Real, h::Real) where {T<:IO}
callback = get_stream_callback(T)
ptr = ccall((:cairo_svg_surface_create_for_stream,libcairo), Ptr{Nothing},
(Ptr{Nothing}, Any, Float64, Float64), callback, stream, w, h)
CairoSurface(ptr, w, h, stream)
surf = CairoSurface(C_NULL, w, h, stream)
GC.@preserve surf begin
surf.ptr = ccall((:cairo_svg_surface_create_for_stream,libcairo), Ptr{Nothing},
(Ptr{Nothing}, Ptr{Nothing}, Float64, Float64), callback,
get_stream_ptr(surf), w, h)
end
return surf
end

function CairoSVGSurface(filename::AbstractString, w::Real, h::Real)
Expand Down Expand Up @@ -464,13 +485,20 @@ mutable struct CairoScript <: GraphicsDevice

function CairoScript(stream::T) where {T<:IO}
callback = get_stream_callback(T)
ptr = ccall((:cairo_script_create_for_stream,libcairo), Ptr{Nothing},
(Ptr{Nothing}, Any), callback, stream)
self = new(ptr,stream)
self = new(C_NULL, stream)
GC.@preserve self begin
self.ptr = ccall((:cairo_script_create_for_stream,libcairo), Ptr{Nothing},
(Ptr{Nothing}, Ptr{Nothing}), callback, get_stream_ptr(self))
end
finalizer(destroy, self)
self
end
end
function get_stream_ptr(s::T) where {T<:CairoScript}
GC.@preserve s begin
return unsafe_load(Ptr{Ptr{Nothing}}(pointer_from_objref(s) + fieldoffset(T, 2)))
end
end

function destroy(s::CairoScript)
if s.ptr == C_NULL
Expand Down

0 comments on commit 73d7f71

Please sign in to comment.