diff options
| author | Přemysl Eric Janouch <p@janouch.name> | 2023-06-23 22:28:09 +0200 | 
|---|---|---|
| committer | Přemysl Eric Janouch <p@janouch.name> | 2023-06-24 14:36:24 +0200 | 
| commit | 074bd4d37f36fa8963e66aa0f8f9de3ff6cadba7 (patch) | |
| tree | c42b57910ac47293fad5d2ac6588ff3da36525e3 /fiv-view.c | |
| parent | add96b37a65fa40e87fd1f3eb9bead896fc2ae8f (diff) | |
| download | fiv-074bd4d37f36fa8963e66aa0f8f9de3ff6cadba7.tar.gz fiv-074bd4d37f36fa8963e66aa0f8f9de3ff6cadba7.tar.xz fiv-074bd4d37f36fa8963e66aa0f8f9de3ff6cadba7.zip  | |
Stop abusing Cairo user data, part 2
With the shift from cairo_surface_t, we've lost our ability
to directly render vector surfaces, but it doesn't matter.
Diffstat (limited to 'fiv-view.c')
| -rw-r--r-- | fiv-view.c | 130 | 
1 files changed, 56 insertions, 74 deletions
@@ -63,10 +63,10 @@ struct _FivView {  	gchar *messages;                    ///< Image load information  	gchar *uri;                         ///< Path to the current image (if any) -	cairo_surface_t *image;             ///< The loaded image (sequence) -	cairo_surface_t *page;              ///< Current page within image, weak -	cairo_surface_t *page_scaled;       ///< Current page within image, scaled -	cairo_surface_t *frame;             ///< Current frame within page, weak +	FivIoImage *image;                  ///< The loaded image (sequence) +	FivIoImage *page;                   ///< Current page within image, weak +	FivIoImage *page_scaled;            ///< Current page within image, scaled +	FivIoImage *frame;                  ///< Current frame within page, weak  	FivIoOrientation orientation;       ///< Current page orientation  	bool enable_cms : 1;                ///< Smooth scaling toggle  	bool filter : 1;                    ///< Smooth scaling toggle @@ -77,7 +77,7 @@ struct _FivView {  	double scale;                       ///< Scaling factor  	double drag_start[2];               ///< Adjustment values for drag origin -	cairo_surface_t *enhance_swap;      ///< Quick swap in/out +	FivIoImage *enhance_swap;           ///< Quick swap in/out  	FivIoProfile screen_cms_profile;    ///< Target colour profile for widget  	int remaining_loops;                ///< Greater than zero if limited @@ -234,9 +234,9 @@ fiv_view_finalize(GObject *gobject)  {  	FivView *self = FIV_VIEW(gobject);  	g_clear_pointer(&self->screen_cms_profile, fiv_io_profile_free); -	g_clear_pointer(&self->enhance_swap, cairo_surface_destroy); -	g_clear_pointer(&self->image, cairo_surface_destroy); -	g_clear_pointer(&self->page_scaled, cairo_surface_destroy); +	g_clear_pointer(&self->enhance_swap, fiv_io_image_unref); +	g_clear_pointer(&self->image, fiv_io_image_unref); +	g_clear_pointer(&self->page_scaled, fiv_io_image_unref);  	g_free(self->uri);  	g_free(self->messages); @@ -283,15 +283,13 @@ fiv_view_get_property(  		g_value_set_boolean(value, !!self->image);  		break;  	case PROP_CAN_ANIMATE: -		g_value_set_boolean(value, self->page && -			cairo_surface_get_user_data(self->page, &fiv_io_key_frame_next)); +		g_value_set_boolean(value, self->page && self->page->frame_next);  		break;  	case PROP_HAS_PREVIOUS_PAGE:  		g_value_set_boolean(value, self->image && self->page != self->image);  		break;  	case PROP_HAS_NEXT_PAGE: -		g_value_set_boolean(value, self->page && -			cairo_surface_get_user_data(self->page, &fiv_io_key_page_next)); +		g_value_set_boolean(value, self->page && self->page->page_next);  		break;  	case PROP_HADJUSTMENT: @@ -403,21 +401,28 @@ static void  prescale_page(FivView *self)  {  	FivIoRenderClosure *closure = NULL; -	if (!self->image || !(closure = -			cairo_surface_get_user_data(self->page, &fiv_io_key_render))) +	if (!self->image || !(closure = self->page->render))  		return;  	// TODO(p): Restart the animation. No vector formats currently animate.  	g_return_if_fail(!self->frame_update_connection);  	// If it fails, the previous frame pointer may become invalid. -	g_clear_pointer(&self->page_scaled, cairo_surface_destroy); +	g_clear_pointer(&self->page_scaled, fiv_io_image_unref);  	self->frame = self->page_scaled = closure->render(closure, self->scale);  	if (!self->page_scaled)  		self->frame = self->page;  }  static void +set_source_image(FivView *self, cairo_t *cr) +{ +	cairo_surface_t *surface = fiv_io_image_to_surface_noref(self->frame); +	cairo_set_source_surface(cr, surface, 0, 0); +	cairo_surface_destroy(surface); +} + +static void  fiv_view_size_allocate(GtkWidget *widget, GtkAllocation *allocation)  {  	GTK_WIDGET_CLASS(fiv_view_parent_class)->size_allocate(widget, allocation); @@ -606,37 +611,19 @@ fiv_view_draw(GtkWidget *widget, cairo_t *cr)  	// Then all frames are pre-scaled.  	if (self->page_scaled) { -		cairo_set_source_surface(cr, self->frame, 0, 0); +		set_source_image(self, cr);  		cairo_pattern_set_matrix(cairo_get_source(cr), &matrix);  		cairo_paint(cr);  		return TRUE;  	} -	// FIXME: Recording surfaces do not work well with CAIRO_SURFACE_TYPE_XLIB, -	// we always get a shitty pixmap, where transparency contains junk. -	if (cairo_surface_get_type(self->frame) == CAIRO_SURFACE_TYPE_RECORDING) { -		cairo_surface_t *image = -			cairo_image_surface_create(CAIRO_FORMAT_ARGB32, dw, dh); -		cairo_t *tcr = cairo_create(image); -		cairo_scale(tcr, self->scale, self->scale); -		cairo_set_source_surface(tcr, self->frame, 0, 0); -		cairo_pattern_set_matrix(cairo_get_source(tcr), &matrix); -		cairo_paint(tcr); -		cairo_destroy(tcr); - -		cairo_set_source_surface(cr, image, 0, 0); -		cairo_paint(cr); -		cairo_surface_destroy(image); -		return TRUE; -	} -  	// XXX: The rounding together with padding may result in up to  	// a pixel's worth of made-up picture data.  	cairo_rectangle(cr, 0, 0, dw, dh);  	cairo_clip(cr);  	cairo_scale(cr, self->scale, self->scale); -	cairo_set_source_surface(cr, self->frame, 0, 0); +	set_source_image(self, cr);  	cairo_pattern_t *pattern = cairo_get_source(cr);  	cairo_pattern_set_matrix(pattern, &matrix); @@ -817,8 +804,7 @@ stop_animating(FivView *self)  static gboolean  advance_frame(FivView *self)  { -	cairo_surface_t *next = -		cairo_surface_get_user_data(self->frame, &fiv_io_key_frame_next); +	FivIoImage *next = self->frame->frame_next;  	if (next) {  		self->frame = next;  	} else { @@ -836,8 +822,7 @@ advance_animation(FivView *self, GdkFrameClock *clock)  	gint64 now = gdk_frame_clock_get_frame_time(clock);  	while (true) {  		// TODO(p): See if infinite frames can actually happen, and how. -		intptr_t duration = (intptr_t) cairo_surface_get_user_data( -			self->frame, &fiv_io_key_frame_duration); +		int64_t duration = self->frame->frame_duration;  		if (duration < 0)  			return FALSE; @@ -875,30 +860,28 @@ start_animating(FivView *self)  	stop_animating(self);  	GdkFrameClock *clock = gtk_widget_get_frame_clock(GTK_WIDGET(self)); -	if (!clock || !self->image || -		!cairo_surface_get_user_data(self->page, &fiv_io_key_frame_next)) +	if (!clock || !self->image || !self->page->frame_next)  		return;  	self->frame_time = gdk_frame_clock_get_frame_time(clock);  	self->frame_update_connection = g_signal_connect(  		clock, "update", G_CALLBACK(on_frame_clock_update), self); -	self->remaining_loops = -		(uintptr_t) cairo_surface_get_user_data(self->page, &fiv_io_key_loops); +	self->remaining_loops = self->page->loops;  	gdk_frame_clock_begin_updating(clock);  	g_object_notify_by_pspec(G_OBJECT(self), view_properties[PROP_PLAYING]);  }  static void -switch_page(FivView *self, cairo_surface_t *page) +switch_page(FivView *self, FivIoImage *page)  { -	g_clear_pointer(&self->page_scaled, cairo_surface_destroy); +	g_clear_pointer(&self->page_scaled, fiv_io_image_unref);  	self->frame = self->page = page;  	prescale_page(self);  	if (!self->page || -		(self->orientation = (uintptr_t) cairo_surface_get_user_data( -			 self->page, &fiv_io_key_orientation)) == FivIoOrientationUnknown) +		(self->orientation = self->page->orientation) == +			FivIoOrientationUnknown)  		self->orientation = FivIoOrientation0;  	start_animating(self); @@ -1027,7 +1010,7 @@ copy(FivView *self)  	cairo_surface_t *transformed =  		cairo_image_surface_create(CAIRO_FORMAT_ARGB32, w, h);  	cairo_t *cr = cairo_create(transformed); -	cairo_set_source_surface(cr, self->frame, 0, 0); +	set_source_image(self, cr);  	cairo_pattern_set_matrix(cairo_get_source(cr), &matrix);  	cairo_paint(cr);  	cairo_destroy(cr); @@ -1065,7 +1048,7 @@ on_draw_page(G_GNUC_UNUSED GtkPrintOperation *operation,  	cairo_t *cr = gtk_print_context_get_cairo_context(context);  	cairo_scale(cr, scale, scale); -	cairo_set_source_surface(cr, self->frame, 0, 0); +	set_source_image(self, cr);  	cairo_pattern_set_matrix(cairo_get_source(cr), &matrix);  	cairo_paint(cr);  } @@ -1100,7 +1083,7 @@ print(FivView *self)  }  static gboolean -save_as(FivView *self, cairo_surface_t *frame) +save_as(FivView *self, FivIoImage *frame)  {  	GtkWindow *window = get_toplevel(GTK_WIDGET(self));  	FivIoProfile target = NULL; @@ -1362,7 +1345,7 @@ fiv_view_init(FivView *self)  // --- Public interface -------------------------------------------------------- -static cairo_surface_t * +static FivIoImage *  open_without_swapping_in(FivView *self, const char *uri)  {  	FivIoOpenContext ctx = { @@ -1374,8 +1357,7 @@ open_without_swapping_in(FivView *self, const char *uri)  	};  	GError *error = NULL; -	cairo_surface_t *surface = -		fiv_io_image_to_surface(fiv_io_open(&ctx, &error)); +	FivIoImage *image = fiv_io_open(&ctx, &error);  	if (error) {  		g_ptr_array_add(ctx.warnings, g_strdup(error->message));  		g_error_free(error); @@ -1388,7 +1370,7 @@ open_without_swapping_in(FivView *self, const char *uri)  	}  	g_ptr_array_free(ctx.warnings, TRUE); -	return surface; +	return image;  }  // TODO(p): Progressive picture loading, or at least async/cancellable. @@ -1396,18 +1378,18 @@ gboolean  fiv_view_set_uri(FivView *self, const char *uri)  {  	// This is extremely expensive, and only works sometimes. -	g_clear_pointer(&self->enhance_swap, cairo_surface_destroy); +	g_clear_pointer(&self->enhance_swap, fiv_io_image_unref);  	if (self->enhance) {  		self->enhance = FALSE;  		g_object_notify_by_pspec(  			G_OBJECT(self), view_properties[PROP_ENHANCE]);  	} -	cairo_surface_t *surface = open_without_swapping_in(self, uri); -	g_clear_pointer(&self->image, cairo_surface_destroy); +	FivIoImage *image = open_without_swapping_in(self, uri); +	g_clear_pointer(&self->image, fiv_io_image_unref);  	self->frame = self->page = NULL; -	self->image = surface; +	self->image = image;  	switch_page(self, self->image);  	// Otherwise, adjustment values and zoom are retained implicitly. @@ -1419,15 +1401,15 @@ fiv_view_set_uri(FivView *self, const char *uri)  	g_object_notify_by_pspec(G_OBJECT(self), view_properties[PROP_MESSAGES]);  	g_object_notify_by_pspec(G_OBJECT(self), view_properties[PROP_HAS_IMAGE]); -	return surface != NULL; +	return image != NULL;  }  static void  page_step(FivView *self, int step)  { -	cairo_user_data_key_t *key = -		step < 0 ? &fiv_io_key_page_previous : &fiv_io_key_page_next; -	cairo_surface_t *page = cairo_surface_get_user_data(self->page, key); +	FivIoImage *page = step < 0 +		? self->page->page_previous +		: self->page->page_next;  	if (page)  		switch_page(self, page);  } @@ -1436,9 +1418,10 @@ static void  frame_step(FivView *self, int step)  {  	stop_animating(self); -	cairo_user_data_key_t *key = -		step < 0 ? &fiv_io_key_frame_previous : &fiv_io_key_frame_next; -	if (!step || !(self->frame = cairo_surface_get_user_data(self->frame, key))) +	FivIoImage *frame = step < 0 +		? self->frame->frame_previous +		: self->frame->frame_next; +	if (!step || !(self->frame = frame))  		self->frame = self->page;  	gtk_widget_queue_draw(GTK_WIDGET(self));  } @@ -1446,21 +1429,21 @@ frame_step(FivView *self, int step)  static gboolean  reload(FivView *self)  { -	cairo_surface_t *surface = open_without_swapping_in(self, self->uri); +	FivIoImage *image = open_without_swapping_in(self, self->uri);  	g_object_notify_by_pspec(G_OBJECT(self), view_properties[PROP_MESSAGES]); -	if (!surface) +	if (!image)  		return FALSE; -	g_clear_pointer(&self->image, cairo_surface_destroy); -	g_clear_pointer(&self->enhance_swap, cairo_surface_destroy); -	switch_page(self, (self->image = surface)); +	g_clear_pointer(&self->image, fiv_io_image_unref); +	g_clear_pointer(&self->enhance_swap, fiv_io_image_unref); +	switch_page(self, (self->image = image));  	return TRUE;  }  static void  swap_enhanced_image(FivView *self)  { -	cairo_surface_t *saved = self->image; +	FivIoImage *saved = self->image;  	self->image = self->page = self->frame = NULL;  	if (self->enhance_swap) { @@ -1547,9 +1530,8 @@ fiv_view_command(FivView *self, FivViewCommand command)  	break; case FIV_VIEW_COMMAND_PAGE_NEXT:  		page_step(self, +1);  	break; case FIV_VIEW_COMMAND_PAGE_LAST: -		for (cairo_surface_t *s = self->page; -			 (s = cairo_surface_get_user_data(s, &fiv_io_key_page_next)); ) -			self->page = s; +		for (FivIoImage *I = self->page; (I = I->page_next); ) +			self->page = I;  		switch_page(self, self->page);  	break; case FIV_VIEW_COMMAND_FRAME_FIRST:  | 
