double page_calc_height_width(zathura_page_t* page, unsigned int* page_height, unsigned int* page_width, bool rotate) { g_return_val_if_fail(page != NULL && page_height != NULL && page_width != NULL, 0.0); zathura_document_t* document = zathura_page_get_document(page); if (document == NULL) { return 0.0; } double height = zathura_page_get_height(page); double width = zathura_page_get_width(page); double scale = zathura_document_get_scale(document); double real_scale; if (rotate && zathura_document_get_rotation(document) % 180) { *page_width = ceil(height * scale); *page_height = ceil(width * scale); real_scale = MAX(*page_width / height, *page_height / width); } else { *page_width = ceil(width * scale); *page_height = ceil(height * scale); real_scale = MAX(*page_width / width, *page_height / height); } return real_scale; }
zathura_rectangle_t recalc_rectangle(zathura_page_t* page, zathura_rectangle_t rectangle) { if (page == NULL) { goto error_ret; } zathura_document_t* document = zathura_page_get_document(page); if (document == NULL) { goto error_ret; } double page_height = zathura_page_get_height(page); double page_width = zathura_page_get_width(page); double scale = zathura_document_get_scale(document); zathura_rectangle_t tmp = rotate_rectangle(rectangle, zathura_document_get_rotation(document), page_height, page_width); tmp.x1 *= scale; tmp.x2 *= scale; tmp.y1 *= scale; tmp.y2 *= scale; return tmp; error_ret: return rectangle; }
static bool draw_page_image(cairo_t* cairo, GtkPrintContext* context, zathura_t* zathura, zathura_page_t* page) { /* Try to render the page on a temporary image surface. */ const double width = gtk_print_context_get_width(context); const double height = gtk_print_context_get_height(context); const double scale_height = 5; const double scale_width = 5; /* Render to a surface that is 5 times larger to workaround quality issues. */ const double page_height = zathura_page_get_height(page) * scale_height; const double page_width = zathura_page_get_width(page) * scale_width; cairo_surface_t* surface = cairo_image_surface_create(CAIRO_FORMAT_RGB24, page_width, page_height); if (surface == NULL) { return false; } if (cairo_surface_status(surface) != CAIRO_STATUS_SUCCESS) { cairo_surface_destroy(surface); return false; } cairo_t* temp_cairo = cairo_create(surface); if (cairo == NULL) { cairo_surface_destroy(surface); return false; } /* Draw a white background. */ cairo_save(temp_cairo); cairo_set_source_rgb(temp_cairo, 1, 1, 1); cairo_rectangle(temp_cairo, 0, 0, page_width, page_height); cairo_fill(temp_cairo); cairo_restore(temp_cairo); /* Render the page to the temporary surface */ zathura_renderer_lock(zathura->sync.render_thread); const int err = zathura_page_render(page, temp_cairo, true); zathura_renderer_unlock(zathura->sync.render_thread); if (err != ZATHURA_ERROR_OK) { cairo_destroy(temp_cairo); cairo_surface_destroy(surface); return false; } /* Rescale the page and keep the aspect ratio */ const gdouble scale = MIN(width / page_width, height / page_height); cairo_scale(cairo, scale, scale); /* Blit temporary surface to original cairo object. */ cairo_set_source_surface(cairo, surface, 0.0, 0.0); cairo_paint(cairo); cairo_destroy(temp_cairo); cairo_surface_destroy(surface); return true; }
void cb_view_vadjustment_value_changed(GtkAdjustment* GIRARA_UNUSED(adjustment), gpointer data) { zathura_t* zathura = data; if (zathura == NULL || zathura->document == NULL || zathura->ui.page_widget == NULL) { return; } GtkAdjustment* view_vadjustment = gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(zathura->ui.session->gtk.view)); GtkAdjustment* view_hadjustment = gtk_scrolled_window_get_hadjustment(GTK_SCROLLED_WINDOW(zathura->ui.session->gtk.view)); GdkRectangle view_rect; /* get current adjustment values */ view_rect.y = 0; view_rect.height = gtk_adjustment_get_page_size(view_vadjustment); view_rect.x = 0; view_rect.width = gtk_adjustment_get_page_size(view_hadjustment); int page_padding = 1; girara_setting_get(zathura->ui.session, "page-padding", &page_padding); GdkRectangle center; center.x = (view_rect.width + 1) / 2; center.y = (view_rect.height + 1) / 2; center.height = center.width = (2 * page_padding) + 1; unsigned int number_of_pages = zathura_document_get_number_of_pages(zathura->document); double scale = zathura_document_get_scale(zathura->document); bool updated = false; /* find page that fits */ for (unsigned int page_id = 0; page_id < number_of_pages; page_id++) { zathura_page_t* page = zathura_document_get_page(zathura->document, page_id); GdkRectangle page_rect; GtkWidget* page_widget = zathura_page_get_widget(zathura, page); gtk_widget_translate_coordinates(page_widget, zathura->ui.session->gtk.view, 0, 0, &page_rect.x, &page_rect.y); page_rect.width = zathura_page_get_width(page) * scale; page_rect.height = zathura_page_get_height(page) * scale; if (gdk_rectangle_intersect(&view_rect, &page_rect, NULL) == TRUE) { zathura_page_set_visibility(page, true); if (zathura->global.update_page_number == true && updated == false && gdk_rectangle_intersect(¢er, &page_rect, NULL) == TRUE) { zathura_document_set_current_page_number(zathura->document, page_id); updated = true; } } else { zathura_page_set_visibility(page, false); } zathura_page_widget_update_view_time(ZATHURA_PAGE(page_widget)); } statusbar_page_number_update(zathura); }
static void cb_print_request_page_setup(GtkPrintOperation* UNUSED(print_operation), GtkPrintContext* UNUSED(context), gint page_number, GtkPageSetup* setup, zathura_t* zathura) { if (zathura == NULL || zathura->document == NULL) { return; } zathura_page_t* page = zathura_document_get_page(zathura->document, page_number); double width = zathura_page_get_width(page); double height = zathura_page_get_height(page); if (width > height) { gtk_page_setup_set_orientation(setup, GTK_PAGE_ORIENTATION_LANDSCAPE); } else { gtk_page_setup_set_orientation(setup, GTK_PAGE_ORIENTATION_PORTRAIT); } }
bool sc_scroll(girara_session_t* session, girara_argument_t* argument, girara_event_t* UNUSED(event), unsigned int UNUSED(t)) { g_return_val_if_fail(session != NULL, false); g_return_val_if_fail(session->global.data != NULL, false); zathura_t* zathura = session->global.data; g_return_val_if_fail(argument != NULL, false); if (zathura->document == NULL) { return false; } GtkAdjustment* adjustment = NULL; if ( (argument->n == LEFT) || (argument->n == FULL_LEFT) || (argument->n == HALF_LEFT) || (argument->n == RIGHT) || (argument->n == FULL_RIGHT) || (argument->n == HALF_RIGHT)) { adjustment = gtk_scrolled_window_get_hadjustment(GTK_SCROLLED_WINDOW(session->gtk.view)); } else { adjustment = gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(session->gtk.view)); } gdouble view_size = gtk_adjustment_get_page_size(adjustment); gdouble value = gtk_adjustment_get_value(adjustment); gdouble max = gtk_adjustment_get_upper(adjustment) - view_size; zathura->global.update_page_number = true; float scroll_step = 40; girara_setting_get(session, "scroll-step", &scroll_step); float scroll_hstep = -1; girara_setting_get(session, "scroll-hstep", &scroll_hstep); if (scroll_hstep < 0) { scroll_hstep = scroll_step; } float scroll_full_overlap = 0.0; girara_setting_get(session, "scroll-full-overlap", &scroll_full_overlap); bool scroll_page_aware = false; girara_setting_get(session, "scroll-page-aware", &scroll_page_aware); bool scroll_wrap = false; girara_setting_get(session, "scroll-wrap", &scroll_wrap); int padding = 1; girara_setting_get(session, "page-padding", &padding); gdouble new_value; switch(argument->n) { case FULL_UP: case FULL_LEFT: new_value = value - (1.0 - scroll_full_overlap) * view_size - padding; break; case FULL_DOWN: case FULL_RIGHT: new_value = value + (1.0 - scroll_full_overlap) * view_size + padding; break; case HALF_UP: case HALF_LEFT: new_value = value - ((view_size + padding) / 2); break; case HALF_DOWN: case HALF_RIGHT: new_value = value + ((view_size + padding) / 2); break; case LEFT: new_value = value - scroll_hstep; break; case UP: new_value = value - scroll_step; break; case RIGHT: new_value = value + scroll_hstep; break; case DOWN: new_value = value + scroll_step; break; case TOP: new_value = 0; break; case BOTTOM: new_value = max; break; default: new_value = value; } if (scroll_wrap == true) { if (new_value < 0) new_value = max; else if (new_value > max) new_value = 0; } if (scroll_page_aware == true) { int page_offset; double page_size; { unsigned int page_id = zathura_document_get_current_page_number(zathura->document); zathura_page_t* page = zathura_document_get_page(zathura->document, page_id); page_offset_t offset; page_calculate_offset(zathura, page, &offset); double scale = zathura_document_get_scale(zathura->document); if ((argument->n == LEFT) || (argument->n == FULL_LEFT) || (argument->n == HALF_LEFT) || (argument->n == RIGHT) || (argument->n == FULL_RIGHT) || (argument->n == HALF_RIGHT)) { page_offset = offset.x; page_size = zathura_page_get_width(page) * scale; } else { page_offset = offset.y; page_size = zathura_page_get_height(page) * scale; } page_offset -= padding / 2; page_size += padding; } if ((argument->n == FULL_DOWN) || (argument->n == HALF_DOWN) || (argument->n == FULL_RIGHT) || (argument->n == HALF_RIGHT)) { if ((page_offset > value) && (page_offset < value + view_size)) { new_value = page_offset; } else if ((page_offset <= value) && (page_offset + page_size < value + view_size)) { new_value = page_offset + page_size + 1; } else if ((page_offset <= value) && (page_offset + page_size < new_value + view_size)) { new_value = page_offset + page_size - view_size + 1; } } else if ((argument->n == FULL_UP) || (argument->n == HALF_UP) || (argument->n == FULL_LEFT) || (argument->n == HALF_LEFT)) { if ((page_offset + 1 >= value) && (page_offset < value + view_size)) { new_value = page_offset - view_size; } else if ((page_offset <= value) && (page_offset + page_size + 1 < value + view_size)) { new_value = page_offset + page_size - view_size; } else if ((page_offset <= value) && (page_offset > new_value)) { new_value = page_offset; } } } set_adjustment(adjustment, new_value); return false; }
zathura_document_t* zathura_document_open(zathura_plugin_manager_t* plugin_manager, const char* path, const char* password, zathura_error_t* error) { if (path == NULL) { return NULL; } if (g_file_test(path, G_FILE_TEST_EXISTS) == FALSE) { girara_error("File '%s' does not exist", path); return NULL; } const gchar* content_type = guess_type(path); if (content_type == NULL) { girara_error("Could not determine file type."); return NULL; } /* determine real path */ long path_max; #ifdef PATH_MAX path_max = PATH_MAX; #else path_max = pathconf(path,_PC_PATH_MAX); if (path_max <= 0) path_max = 4096; #endif char* real_path = NULL; zathura_document_t* document = NULL; real_path = malloc(sizeof(char) * path_max); if (real_path == NULL) { g_free((void*)content_type); return NULL; } if (realpath(path, real_path) == NULL) { g_free((void*)content_type); free(real_path); return NULL; } zathura_plugin_t* plugin = zathura_plugin_manager_get_plugin(plugin_manager, content_type); g_free((void*)content_type); if (plugin == NULL) { girara_error("unknown file type\n"); *error = ZATHURA_ERROR_UNKNOWN; goto error_free; } document = g_malloc0(sizeof(zathura_document_t)); document->file_path = real_path; document->basename = g_path_get_basename(real_path); document->password = password; document->scale = 1.0; document->plugin = plugin; document->adjust_mode = ZATHURA_ADJUST_NONE; document->cell_width = 0.0; document->cell_height = 0.0; document->view_height = 0; document->view_width = 0; document->position_x = 0.0; document->position_y = 0.0; /* open document */ zathura_plugin_functions_t* functions = zathura_plugin_get_functions(plugin); if (functions->document_open == NULL) { girara_error("plugin has no open function\n"); goto error_free; } zathura_error_t int_error = functions->document_open(document); if (int_error != ZATHURA_ERROR_OK) { if (error != NULL) { *error = int_error; } girara_error("could not open document\n"); goto error_free; } /* read all pages */ document->pages = calloc(document->number_of_pages, sizeof(zathura_page_t*)); if (document->pages == NULL) { goto error_free; } for (unsigned int page_id = 0; page_id < document->number_of_pages; page_id++) { zathura_page_t* page = zathura_page_new(document, page_id, NULL); if (page == NULL) { goto error_free; } document->pages[page_id] = page; /* cell_width and cell_height is the maximum of all the pages width and height */ const double width = zathura_page_get_width(page); if (document->cell_width < width) document->cell_width = width; const double height = zathura_page_get_height(page); if (document->cell_height < height) document->cell_height = height; } return document; error_free: free(real_path); if (document != NULL && document->pages != NULL) { for (unsigned int page_id = 0; page_id < document->number_of_pages; page_id++) { zathura_page_free(document->pages[page_id]); } free(document->pages); } g_free(document); return NULL; }
void cb_view_vadjustment_value_changed(GtkAdjustment* GIRARA_UNUSED(adjustment), gpointer data) { zathura_t* zathura = data; if (zathura == NULL || zathura->document == NULL || zathura->ui.page_widget == NULL) { return; } GtkAdjustment* view_vadjustment = gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(zathura->ui.session->gtk.view)); GtkAdjustment* view_hadjustment = gtk_scrolled_window_get_hadjustment(GTK_SCROLLED_WINDOW(zathura->ui.session->gtk.view)); /* current adjustment values */ GdkRectangle view_rect = { .x = 0, .y = 0, .width = gtk_adjustment_get_page_size(view_hadjustment), .height = gtk_adjustment_get_page_size(view_vadjustment) }; int page_padding = 1; girara_setting_get(zathura->ui.session, "page-padding", &page_padding); GdkRectangle center = { .x = (view_rect.width + 1) / 2, .y = (view_rect.height + 1) / 2, .width = (2 * page_padding) + 1, .height = (2 * page_padding) + 1 }; unsigned int number_of_pages = zathura_document_get_number_of_pages(zathura->document); double scale = zathura_document_get_scale(zathura->document); bool updated = false; /* find page that fits */ for (unsigned int page_id = 0; page_id < number_of_pages; page_id++) { zathura_page_t* page = zathura_document_get_page(zathura->document, page_id); GdkRectangle page_rect = { .width = zathura_page_get_width(page) * scale, .height = zathura_page_get_height(page) * scale }; GtkWidget* page_widget = zathura_page_get_widget(zathura, page); gtk_widget_translate_coordinates(page_widget, zathura->ui.session->gtk.view, 0, 0, &page_rect.x, &page_rect.y); if (gdk_rectangle_intersect(&view_rect, &page_rect, NULL) == TRUE) { zathura_page_set_visibility(page, true); if (zathura->global.update_page_number == true && updated == false && gdk_rectangle_intersect(¢er, &page_rect, NULL) == TRUE) { zathura_document_set_current_page_number(zathura->document, page_id); updated = true; } } else { zathura_page_set_visibility(page, false); } zathura_page_widget_update_view_time(ZATHURA_PAGE(page_widget)); } statusbar_page_number_update(zathura); } void cb_pages_per_row_value_changed(girara_session_t* session, const char* UNUSED(name), girara_setting_type_t UNUSED(type), void* value, void* UNUSED(data)) { g_return_if_fail(value != NULL); g_return_if_fail(session != NULL); g_return_if_fail(session->global.data != NULL); zathura_t* zathura = session->global.data; int pages_per_row = *(int*) value; if (pages_per_row < 1) { pages_per_row = 1; } unsigned int first_page_column = 1; girara_setting_get(session, "first-page-column", &first_page_column); page_widget_set_mode(zathura, pages_per_row, first_page_column); if (zathura->document != NULL) { unsigned int current_page = zathura_document_get_current_page_number(zathura->document); page_set_delayed(zathura, current_page); } }
zathura_image_buffer_t* djvu_page_render(zathura_page_t* page, void* UNUSED(data), zathura_error_t* error) { if (page == NULL) { if (error != NULL) { *error = ZATHURA_ERROR_INVALID_ARGUMENTS; } return NULL; } zathura_document_t* document = zathura_page_get_document(page); if (document == NULL) { return NULL; } /* calculate sizes */ unsigned int page_width = zathura_document_get_scale(document) * zathura_page_get_width(page); unsigned int page_height = zathura_document_get_scale(document) * zathura_page_get_height(page); if (page_width == 0 || page_height == 0) { if (error != NULL) { *error = ZATHURA_ERROR_UNKNOWN; } goto error_out; } /* init ddjvu render data */ djvu_document_t* djvu_document = zathura_document_get_data(document); ddjvu_page_t* djvu_page = ddjvu_page_create_by_pageno( djvu_document->document, zathura_page_get_index(page)); if (djvu_page == NULL) { if (error != NULL) { *error = ZATHURA_ERROR_UNKNOWN; } goto error_out; } while (!ddjvu_page_decoding_done(djvu_page)) { handle_messages(djvu_document, true); } ddjvu_rect_t rrect = { 0, 0, page_width, page_height }; ddjvu_rect_t prect = { 0, 0, page_width, page_height }; zathura_image_buffer_t* image_buffer = zathura_image_buffer_create(page_width, page_height); if (image_buffer == NULL) { if (error != NULL) { *error = ZATHURA_ERROR_OUT_OF_MEMORY; } goto error_free; } /* set rotation */ ddjvu_page_set_rotation(djvu_page, DDJVU_ROTATE_0); /* render page */ ddjvu_page_render(djvu_page, DDJVU_RENDER_COLOR, &prect, &rrect, djvu_document->format, 3 * page_width, (char*) image_buffer->data); return image_buffer; error_free: ddjvu_page_release(djvu_page); zathura_image_buffer_free(image_buffer); error_out: return NULL; }
char* djvu_page_get_text(zathura_page_t* page, void* UNUSED(data), zathura_rectangle_t rectangle, zathura_error_t* error) { if (page == NULL) { if (error != NULL) { *error = ZATHURA_ERROR_INVALID_ARGUMENTS; } goto error_ret; } zathura_document_t* document = zathura_page_get_document(page); if (document == NULL) { goto error_ret; } djvu_document_t* djvu_document = zathura_document_get_data(document); djvu_page_text_t* page_text = djvu_page_text_new(djvu_document, page); if (page_text == NULL) { goto error_ret; } double tmp = 0; double page_height = zathura_page_get_height(page); double page_width = zathura_page_get_width(page); switch (zathura_document_get_rotation(document)) { case 90: tmp = rectangle.x1; rectangle.x1 = rectangle.y1; rectangle.y1 = tmp; tmp = rectangle.x2; rectangle.x2 = rectangle.y2; rectangle.y2 = tmp; break; case 180: tmp = rectangle.x1; rectangle.x1 = (page_width - rectangle.x2); rectangle.x2 = (page_width - tmp); break; case 270: tmp = rectangle.y2; rectangle.y2 = (page_height - rectangle.x1); rectangle.x1 = (page_width - tmp); tmp = rectangle.y1; rectangle.y1 = (page_height - rectangle.x2); rectangle.x2 = (page_width - tmp); break; default: tmp = rectangle.y1; rectangle.y1 = (page_height - rectangle.y2); rectangle.y2 = (page_height - tmp); break; } /* adjust to scale */ rectangle.x1 /= ZATHURA_DJVU_SCALE; rectangle.x2 /= ZATHURA_DJVU_SCALE; rectangle.y1 /= ZATHURA_DJVU_SCALE; rectangle.y2 /= ZATHURA_DJVU_SCALE; char* text = djvu_page_text_select(page_text, rectangle); djvu_page_text_free(page_text); return text; error_ret: if (error != NULL && *error == ZATHURA_ERROR_OK) { *error = ZATHURA_ERROR_UNKNOWN; } return NULL; }
static void cb_print_draw_page(GtkPrintOperation* print_operation, GtkPrintContext* context, gint page_number, zathura_t* zathura) { if (context == NULL || zathura == NULL || zathura->document == NULL || zathura->ui.session == NULL || zathura->ui.statusbar.file == NULL) { gtk_print_operation_cancel(print_operation); return; } /* Update statusbar. */ char* tmp = g_strdup_printf("Printing %d...", page_number); girara_statusbar_item_set_text(zathura->ui.session, zathura->ui.statusbar.file, tmp); g_free(tmp); /* Get the page and cairo handle. */ cairo_t* cairo = gtk_print_context_get_cairo_context(context); zathura_page_t* page = zathura_document_get_page(zathura->document, page_number); if (cairo == NULL || page == NULL) { gtk_print_operation_cancel(print_operation); return; } /* Try to render the page without a temporary surface. This only works with * plugins that support rendering to any surface. */ girara_debug("printing page %d ...", page_number); zathura_renderer_lock(zathura->sync.render_thread); int err = zathura_page_render(page, cairo, true); zathura_renderer_unlock(zathura->sync.render_thread); if (err == ZATHURA_ERROR_OK) { return; } /* Try to render the page on a temporary image surface. */ const gdouble width = gtk_print_context_get_width(context); const gdouble height = gtk_print_context_get_height(context); /* Render to a surface that is 5 times larger to workaround quality issues. */ const double page_height = zathura_page_get_height(page) * 5; const double page_width = zathura_page_get_width(page) * 5; cairo_surface_t* surface = cairo_image_surface_create(CAIRO_FORMAT_RGB24, page_width, page_height); if (surface == NULL) { gtk_print_operation_cancel(print_operation); return; } cairo_t* temp_cairo = cairo_create(surface); if (cairo == NULL) { gtk_print_operation_cancel(print_operation); cairo_surface_destroy(surface); return; } /* Draw a white background. */ cairo_save(temp_cairo); cairo_set_source_rgb(temp_cairo, 1, 1, 1); cairo_rectangle(temp_cairo, 0, 0, page_width, page_height); cairo_fill(temp_cairo); cairo_restore(temp_cairo); /* Render the page to the temporary surface */ girara_debug("printing page %d (fallback) ...", page_number); zathura_renderer_lock(zathura->sync.render_thread); err = zathura_page_render(page, temp_cairo, true); zathura_renderer_unlock(zathura->sync.render_thread); if (err != ZATHURA_ERROR_OK) { cairo_destroy(temp_cairo); cairo_surface_destroy(surface); gtk_print_operation_cancel(print_operation); return; } /* Rescale the page and keep the aspect ratio */ const gdouble scale = MIN(width / page_width, height / page_height); cairo_scale(cairo, scale, scale); /* Blit temporary surface to original cairo object. */ cairo_set_source_surface(cairo, surface, 0.0, 0.0); cairo_paint(cairo); cairo_destroy(temp_cairo); cairo_surface_destroy(surface); }