+static void
+ev_view_get_offsets (EvView *view, int *x_offset, int *y_offset)
+{
+ EvDocument *document = view->document;
+ GtkWidget *widget = GTK_WIDGET (view);
+ int width, height, target_width, target_height;
+
+ g_return_if_fail (EV_IS_DOCUMENT (document));
+
+ ev_page_cache_get_size (view->page_cache,
+ view->current_page,
+ view->scale,
+ &width, &height);
+
+ *x_offset = view->spacing;
+ *y_offset = view->spacing;
+ target_width = width + view->border.left +
+ view->border.right + view->spacing * 2;
+ target_height = height + view->border.top +
+ view->border.bottom + view->spacing * 2;
+ *x_offset += MAX (0, (widget->allocation.width - target_width) / 2);
+ *y_offset += MAX (0, (widget->allocation.height - target_height) / 2);
+}
+
+static void
+view_rect_to_doc_rect (EvView *view, GdkRectangle *view_rect, EvRectangle *doc_rect)
+{
+ int x_offset, y_offset;
+
+ ev_view_get_offsets (view, &x_offset, &y_offset);
+ doc_rect->x1 = (double) (view_rect->x - x_offset) / view->scale;
+ doc_rect->y1 = (double) (view_rect->y - y_offset) / view->scale;
+ doc_rect->x2 = doc_rect->x1 + (double) view_rect->width / view->scale;
+ doc_rect->y2 = doc_rect->y1 + (double) view_rect->height / view->scale;
+}
+
+static void
+doc_rect_to_view_rect (EvView *view, EvRectangle *doc_rect, GdkRectangle *view_rect)
+{
+ int x_offset, y_offset;
+
+ ev_view_get_offsets (view, &x_offset, &y_offset);
+ view_rect->x = floor (doc_rect->x1 * view->scale) + x_offset;
+ view_rect->y = floor (doc_rect->y1 * view->scale) + y_offset;
+ view_rect->width = ceil (doc_rect->x2 * view->scale) + x_offset - view_rect->x;
+ view_rect->height = ceil (doc_rect->y2 * view->scale) + y_offset - view_rect->y;
+}
+
+static void
+compute_border (EvView *view, int width, int height, GtkBorder *border)
+{
+ if (view->show_border) {
+ ev_document_misc_get_page_border_size (width, height, border);
+ } else {
+ border->left = 0;
+ border->right = 0;
+ border->top = 0;
+ border->bottom = 0;
+ }
+}
+
+static void
+compute_zoom_factor (EvView *view)
+{
+ int doc_width, doc_height;
+ double scale, scale_w, scale_h;
+ GtkBorder border;
+
+ if (view->width <= 0 && view->height <= 0) {
+ return;
+ }
+
+ doc_width = doc_height = 0;
+ scale = scale_w = scale_h = 1.0;
+ ev_page_cache_get_size (view->page_cache,
+ view->current_page,
+ 1.0,
+ &doc_width,
+ &doc_height);
+
+ compute_border (view, doc_width, doc_height, &border);
+
+ if (doc_width == 0 || doc_height == 0) {
+ return;
+ }
+
+ if (view->width >= 0) {
+ int target_width;
+
+ target_width = view->width - (view->spacing * 2 + view->border.left +
+ view->border.right);
+ scale = scale_w = (double)target_width / doc_width;
+ }
+
+ if (view->height >= 0) {
+ int target_height;
+
+ target_height = view->height - (view->spacing * 2 + view->border.top +
+ view->border.bottom);
+ scale = scale_h = (double)target_height / doc_height;
+ }
+
+ if (view->width >= 0 && view->height >= 0) {
+ scale = (scale_w < scale_h) ? scale_w : scale_h;
+ }
+
+ view->scale = scale;
+}
+
+/* Called by size_request to make sure we have appropriate jobs running.
+ */