void pango_render_text_shadow(cairo_t *context, PangoLayout *layout)
{
	cairo_push_group(context);

	cairo_new_path(context);
	cairo_move_to(context, 15.0+8.0, 10.0+8.0);

	pango_cairo_layout_path(context, layout);

	cairo_set_line_width(context, 6.0);
	cairo_set_miter_limit(context, 2.0);

	cairo_set_source_rgb(context, 0.0, 0.0, 0.0);
	cairo_stroke_preserve(context);

	cairo_fill(context);

	cairo_pop_group_to_source(context);
	cairo_paint_with_alpha(context, 0.6);

	cairo_new_path(context);
	cairo_move_to(context, 15.0, 10.0);

	pango_cairo_layout_path(context, layout);

	cairo_set_line_width(context, 6.0);
	cairo_set_miter_limit(context, 2.0);

	cairo_set_source_rgb(context, 0.0, 0.3, 0.9);
	cairo_stroke_preserve(context);

	cairo_set_source_rgb(context, 0.9, 0.1, 0.8);
	cairo_fill(context);
}
Beispiel #2
0
void ZDrawSongInfo(IDirectFB *dfb, IDirectFBSurface *dfbsurface, const gchar *title, const gchar *artist, 
		gint w, gint h, DFBColor *color, DFBColor *strokeColor, double strokeWidth, const PangoFontDescription *desc)
{
	cairo_t *cr = NULL;
	cairo_surface_t *surface = NULL;
	cairo_surface_t *cairosurface = NULL;
	PangoLayout *layout = NULL;
	
	if(!dfb || !dfbsurface)
		return;
	
	/* prepare layout */
	layout = pango_layout_new(gdk_pango_context_get());
	pango_layout_set_single_paragraph_mode (layout, TRUE);
	pango_layout_set_alignment(layout, PANGO_ALIGN_CENTER);
	pango_layout_set_width(layout, w* PANGO_SCALE);
	pango_layout_set_font_description(layout, desc);
	
	surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, w, h);
	cr = cairo_create(surface);
	
	/* Draw title */
	if(title) {
		pango_layout_set_text(layout, title, -1);
		cairo_move_to(cr, 0, 0);
		pango_cairo_layout_path(cr, layout);
		ZCairoSetDFBColor(cr, strokeColor);
		cairo_set_line_width(cr, strokeWidth);
		cairo_stroke_preserve(cr);
		
		ZCairoSetDFBColor(cr, color);
		cairo_fill(cr);
	}
	
	/* Draw artist */
	if(artist) {
		pango_layout_set_text(layout, artist, -1);
		cairo_move_to(cr, 0, h/2);
		pango_cairo_layout_path(cr, layout);
		ZCairoSetDFBColor(cr, strokeColor);
		cairo_set_line_width(cr, strokeWidth);
		cairo_stroke_preserve(cr);
		
		ZCairoSetDFBColor(cr, color);
		cairo_fill(cr);
	}
	
	g_object_unref(layout);
	cairo_destroy(cr);
	
	/* Draw cairo_surface to dfbsurface */
	/* create surface */
	cairosurface = cairo_directfb_surface_create(dfb, dfbsurface);
	cr = cairo_create(cairosurface);
	cairo_set_source_surface(cr, surface, 0, 0);
	cairo_paint(cr);
	cairo_destroy(cr);
	cairo_surface_destroy(surface);
	cairo_surface_destroy(cairosurface);
}
Beispiel #3
0
void ZCairoDrawLyric(cairo_t *cr, gboolean isUpLine, 
				gint space, gint w, gint h, 
				DFBColor *bgColor, const gchar *text, gint fullWidth, 
				DFBColor *color1, DFBColor *strokeColor1, double strokeWidth1, 
				DFBColor *color2, DFBColor *strokeColor2, double strokeWidth2, 
				const PangoFontDescription *desc)
{
	PangoLayout *layout = NULL;
	gint x, y;
	
	/* Prepare layout */
	layout = pango_layout_new(gdk_pango_context_get());
	pango_layout_set_single_paragraph_mode (layout, TRUE);
	pango_layout_set_alignment(layout, isUpLine ? PANGO_ALIGN_LEFT : PANGO_ALIGN_RIGHT);
	pango_layout_set_font_description(layout, desc);
	pango_layout_set_text(layout, text, -1);
	
	/* Clear background */
	cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR);
	cairo_paint(cr);
	cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
	
	/* Draw background */
	if(bgColor) {
		ZCairoSetDFBColor(cr, bgColor);
		cairo_paint(cr);
	}
	
	/* Draw original text */
	x = isUpLine ? space : w - fullWidth - space;
	y = 0;
	cairo_move_to(cr, x, y);
	pango_cairo_layout_path(cr, layout);
	ZCairoSetDFBColor(cr, strokeColor1);
	cairo_set_line_width(cr, strokeWidth1);
	cairo_stroke_preserve(cr);
	
	ZCairoSetDFBColor(cr, color1);
	cairo_fill(cr);
	
	/* Draw effect text */
	y = h/2;
	cairo_move_to(cr, x, y);
	pango_cairo_layout_path(cr, layout);
	ZCairoSetDFBColor(cr, strokeColor2);
	cairo_set_line_width(cr, strokeWidth2);
	cairo_stroke_preserve(cr);
	
	ZCairoSetDFBColor(cr, color2);
	cairo_fill(cr);
	
	g_object_unref(layout);
}
/* Draws a rounded rectangle with text inside. */
static gboolean
numbers_draw_cb (GtkWidget *widget, cairo_t *ctx, gpointer data)
{
	double x, y, w, h;
	PangoLayout * layout;
	gint font_size = gtk_widget_get_font_size (widget);

	#if (INDICATOR_MESSAGES_HAS_LOZENGE == 1)
	gboolean is_lozenge = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (widget), "is-lozenge"));
	/* let the label handle the drawing if it's not a lozenge */
	if (!is_lozenge)
		return FALSE;
	#endif

	if (!GTK_IS_WIDGET (widget)) return FALSE;

	/* get style + arrow position / dimensions */
	double red, green, blue;
	GtkStyleContext *style = gtk_widget_get_style_context (widget);
	GdkRGBA color;
	gtk_style_context_get_color (style, gtk_widget_get_state(widget), &color);
	red = color.red;
	green = color.green;
	blue = color.blue;
	GtkAllocation allocation;
	gtk_widget_get_allocation (widget, &allocation);
	w = allocation.width;
	h = allocation.height;
	x = y = 0;

	layout = gtk_label_get_layout (GTK_LABEL(widget));
	PangoRectangle layout_extents;
	pango_layout_get_extents (layout, NULL, &layout_extents);
	pango_extents_to_pixels (&layout_extents, NULL);

	if (layout_extents.width == 0)
		return TRUE;

	cairo_set_line_width (ctx, 1.0);

	cairo_set_fill_rule (ctx, CAIRO_FILL_RULE_EVEN_ODD);

	/* cairo drawing code */
	custom_cairo_rounded_rectangle (ctx, x - font_size/2.0, y, w + font_size, h);

	cairo_set_source_rgba (ctx, red,
	                           green,
	                           blue, 0.5);

	x += (allocation.width - layout_extents.width) / 2.0;
	y += (allocation.height - layout_extents.height) / 2.0;
	cairo_move_to (ctx, floor (x), floor (y));
	pango_cairo_layout_path (ctx, layout);
	cairo_fill (ctx);

	return TRUE;
}
void
ol_osd_render_paint_text (OlOsdRenderContext *context,
                          cairo_t *cr,
                          const char *text,
                          double xpos,
                          double ypos)
{
  ol_assert (context != NULL);
  ol_assert (cr != NULL);
  ol_assert (text != NULL);
  ol_osd_render_set_text (context, text);
  int width, height;
  xpos += context->outline_width / 2.0 + context->blur_radius;
  ypos += context->outline_width / 2.0 + context->blur_radius;
  pango_layout_get_pixel_size (context->pango_layout, &width, &height);
  /* draws the outline of the text */
  cairo_move_to (cr, xpos, ypos);
  cairo_save (cr);
  pango_cairo_layout_path(cr, context->pango_layout);
  cairo_set_source_rgb (cr, ol_color_black.r, ol_color_black.g, ol_color_black.b);
  if (context->outline_width > 0)
  {
    cairo_set_line_width (cr, context->outline_width);
    if (context->blur_radius > 1e-4)
    {
      cairo_stroke_preserve (cr);
      cairo_fill (cr);
      ol_gussian_blur (cairo_get_target (cr), context->blur_radius);
    }
    else
    {
      cairo_stroke (cr);
    }
  }
  cairo_restore (cr);
  cairo_save (cr);
  cairo_new_path (cr);
  /* creates the linear pattern */
  cairo_pattern_t *pattern = cairo_pattern_create_linear (xpos, ypos, xpos, ypos + height);
  int i;
  for (i = 0; i < OL_LINEAR_COLOR_COUNT; i++)
  {
    cairo_pattern_add_color_stop_rgb(pattern,
                                     context->linear_pos[i],
                                     context->linear_colors[i].r,
                                     context->linear_colors[i].g,
                                     context->linear_colors[i].b);
  }
  cairo_set_source (cr, pattern);
  cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
  /* draws the text */
  cairo_move_to (cr, xpos, ypos);
  pango_cairo_show_layout (cr, context->pango_layout);
  cairo_pattern_destroy (pattern);
  cairo_restore (cr);
}
void pango_render_text_simple(cairo_t *context, PangoLayout *layout)
{
	cairo_new_path(context);
	cairo_move_to(context, 15.0, 10.0);

	pango_cairo_layout_path(context, layout);

	cairo_set_source_rgb(context, 0.9, 0.1, 0.8);
	cairo_fill(context);
}
PP_Bool
ppb_browser_font_trusted_draw_text_at(PP_Resource font, PP_Resource image_data,
                                      const struct PP_BrowserFont_Trusted_TextRun *text,
                                      const struct PP_Point *position, uint32_t color,
                                      const struct PP_Rect *clip, PP_Bool image_data_is_opaque)
{
    (void)image_data_is_opaque; // TODO: is it worth implementing?
    struct pp_browser_font_s *bf = pp_resource_acquire(font, PP_RESOURCE_BROWSER_FONT);
    if (!bf)
        return PP_FALSE;
    struct pp_image_data_s *id = pp_resource_acquire(image_data, PP_RESOURCE_IMAGE_DATA);
    if (!id) {
        pp_resource_release(font);
        return PP_FALSE;
    }

    cairo_t *cr = cairo_create(id->cairo_surf);
    if (clip) {
        cairo_rectangle(cr, clip->point.x, clip->point.y, clip->size.width, clip->size.height);
        cairo_clip(cr);
    }

    PangoFontMetrics *m = pango_font_get_metrics(bf->font, NULL);
    int32_t ascent = pango_font_metrics_get_ascent(m) / PANGO_SCALE;
    cairo_surface_mark_dirty(id->cairo_surf);
    if (position)
        cairo_move_to(cr, position->x, position->y - ascent);
    else
        cairo_move_to(cr, 0, 0);
    pango_font_metrics_unref(m);

    cairo_set_source_rgba(cr, ((color >> 16) & 0xffu) / 255.0,
                              ((color >> 8) & 0xffu) / 255.0,
                              ((color >> 0) & 0xffu) / 255.0,
                              ((color >> 24) & 0xffu) / 255.0);

    PangoLayout *layout = pango_cairo_create_layout(cr);
    uint32_t len = 0;
    const char *s = "";
    if (text->text.type == PP_VARTYPE_STRING)
        s = ppb_var_var_to_utf8(text->text, &len);

    // TODO: factor into rtl direction
    pango_layout_set_font_description(layout, bf->font_desc);
    pango_layout_set_text(layout, s, len);
    pango_cairo_layout_path(cr, layout);
    cairo_fill(cr);
    g_object_unref(layout);
    cairo_surface_flush(id->cairo_surf);
    cairo_destroy(cr);

    pp_resource_release(font);
    pp_resource_release(image_data);
    return PP_FALSE;
}
			void GuiSolidLabelElementRenderer::Render(Rect bounds)
			{
				if(cairoContext)
				{
					cairo_save(cairoContext);
					Color color = element->GetColor();
					FontProperties font = element->GetFont();

					cairo_set_source_rgba(cairoContext, 
							1.0 * color.r / 255, 
							1.0 * color.g / 255, 
							1.0 * color.b / 255,
							1.0 * color.a / 255
							);

					if(element->GetWrapLine()) pango_layout_set_width(layout, bounds.Width() * PANGO_SCALE);
					pango_cairo_update_layout(cairoContext, layout);
					int layoutWidth, layoutHeight;
					int plotX1, plotY1;

					pango_layout_get_pixel_size( layout, &layoutWidth, &layoutHeight);
					switch(element->GetHorizontalAlignment())
					{
					case Alignment::Left:
						plotX1 = bounds.x1;
						break;
					case Alignment::Center:
						plotX1 = bounds.x1 + (bounds.Width() - layoutWidth) / 2;
						break;
					case Alignment::Right:
						plotX1 = bounds.x1 + (bounds.Width() - layoutWidth);
						break;
					}

					switch(element->GetVerticalAlignment())
					{
					case Alignment::Top:
						plotY1 = bounds.y1;
						break;
					case Alignment::Center:
						plotY1 = bounds.y1 + (bounds.Height() - layoutHeight) / 2;
						break;
					case Alignment::Bottom:
						plotY1 = bounds.y1 + (bounds.Height() - layoutHeight);
						break;
					}

					cairo_move_to(cairoContext, plotX1, plotY1);

					pango_cairo_layout_path(cairoContext, layout);
					cairo_fill(cairoContext);

					cairo_restore(cairoContext);
				}
			}
Beispiel #9
0
static void
draw_page (GtkPrintOperation *operation,
	   GtkPrintContext *context,
	   int page_nr)
{
  cairo_t *cr;
  PangoLayout *layout;
  PangoFontDescription *desc;
  
  cr = gtk_print_context_get_cairo_context (context);

  /* Draw a red rectangle, as wide as the paper (inside the margins) */
  cairo_set_source_rgb (cr, 1.0, 0, 0);
  cairo_rectangle (cr, 0, 0, gtk_print_context_get_width (context), 50);
  
  cairo_fill (cr);

  /* Draw some lines */
  cairo_move_to (cr, 20, 10);
  cairo_line_to (cr, 40, 20);
  cairo_arc (cr, 60, 60, 20, 0, G_PI);
  cairo_line_to (cr, 80, 20);
  
  cairo_set_source_rgb (cr, 0, 0, 0);
  cairo_set_line_width (cr, 5);
  cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND);
  cairo_set_line_join (cr, CAIRO_LINE_JOIN_ROUND);
  
  cairo_stroke (cr);

  /* Draw some text */
  
  layout = gtk_print_context_create_pango_layout (context);
  pango_layout_set_text (layout, "Hello World! Printing is easy", -1);
  desc = pango_font_description_from_string ("sans 28");
  pango_layout_set_font_description (layout, desc);
  pango_font_description_free (desc);

  cairo_move_to (cr, 30, 20);
  pango_cairo_layout_path (cr, layout);

  /* Font Outline */
  cairo_set_source_rgb (cr, 0.93, 1.0, 0.47);
  cairo_set_line_width (cr, 0.5);
  cairo_stroke_preserve (cr);

  /* Font Fill */
  cairo_set_source_rgb (cr, 0, 0.0, 1.0);
  cairo_fill (cr);

  g_object_unref (layout);
}
Beispiel #10
0
void
TextAsset::drawText(cairo_t* cairoContext,
                    const std::string& textString,
                    const Rect& rect,
                    PangoFontDescription* inFontDescription,
                    bool outlineEnabled)
{
    cairo_move_to(cairoContext, rect.x, rect.y);

    PangoLayout* layout = pango_cairo_create_layout(cairoContext);

    // Kerning
    PangoAttrList* attr_list = pango_attr_list_new();
    PangoAttribute* spacing_attr = pango_attr_letter_spacing_new(pango_units_from_double(_kern));
    pango_attr_list_insert(attr_list, spacing_attr);
    pango_layout_set_attributes(layout, attr_list);

    pango_cairo_context_set_resolution(pango_layout_get_context(layout), DISPLAY_RESOLUTION);
    pango_layout_set_text(layout, textString.c_str(), textString.length());
    pango_layout_set_font_description(layout, inFontDescription);
    pango_layout_set_wrap(layout, PANGO_WRAP_WORD_CHAR);
    pango_layout_set_width(layout, pango_units_from_double(rect.size.width + WIDTH_PADDING));
    pango_layout_set_height(layout, pango_units_from_double(rect.size.height + HEIGHT_PADDING));
    pango_layout_set_alignment(layout, _alignment);
    applyLeading(cairoContext, layout, inFontDescription);

    pango_cairo_show_layout(cairoContext, layout);

    // Core Text defines positive outline width values as stroke only
    if (_outlineThickness <= 0.0f) {
        cairo_fill_preserve(cairoContext);
    }

    // Outline
    if (outlineEnabled && _outlineThickness != 0.0f) {
        const float outlineThickness = (fabsf(_outlineThickness) / 100.0f) * _fontSize * CLIENT_TO_SERVER_SCALE;
        cairo_set_source_rgba(cairoContext,
                              _outlineColor.red,
                              _outlineColor.green,
                              _outlineColor.blue,
                              _outlineColor.alpha);
        pango_cairo_layout_path(cairoContext, layout);
        cairo_set_line_width(cairoContext, outlineThickness);
        cairo_stroke(cairoContext);
    } else {
        cairo_new_path(cairoContext);
    }

    g_object_unref(layout);
}
Beispiel #11
0
static void br_cairo_draw_tooltip(duc_graph *g, double x, double y, char *text)
{
	struct cairo_backend_data *bd = g->backend_data;
	cairo_t *cr = bd->cr;

	char font[32];
	snprintf(font, sizeof font, "Arial, Sans, %d", FONT_SIZE_TOOLTIP);
	PangoLayout *layout = pango_cairo_create_layout(cr);
	PangoFontDescription *desc = pango_font_description_from_string(font);

	pango_layout_set_text(layout, text, -1);
	pango_layout_set_font_description(layout, desc);
	pango_font_description_free(desc);

	pango_cairo_update_layout(cr, layout);

	int w,h;
	pango_layout_get_size(layout, &w, &h);

	w /= PANGO_SCALE;
	h /= PANGO_SCALE;

	/* shadow box */

	int i;
	for(i=1; i<3; i++) {
		cairo_rectangle(cr, x - w - 10 + i, y - h - 10 + i, w + 10 + i, h + 10 + i);
		cairo_set_source_rgba(cr, 0, 0, 0, 0.25);
		cairo_fill(cr);
	}

	/* tooltip box */

	cairo_rectangle(cr, x - w - 10 + 0.5, y - h - 10 + 0.5, w + 10, h + 10);
	cairo_set_source_rgba(cr, 1, 1, 1, 1);
	cairo_fill_preserve(cr);
	cairo_set_source_rgba(cr, 0, 0, 0, 1);
	cairo_stroke(cr);
	
	/* black text */

	cairo_move_to(cr, x - w - 5, y - h - 5);
	pango_cairo_layout_path(cr, layout);
	g_object_unref(layout);

	cairo_set_source_rgb(cr, 0, 0, 0);
	cairo_set_line_width(cr, 1);
	cairo_fill(cr);
}
void pango_render_text_border(cairo_t *context, PangoLayout *layout)
{
	cairo_new_path(context);
	cairo_move_to(context, 15.0, 10.0);

	pango_cairo_layout_path(context, layout);

	cairo_set_line_width(context, 6.0);
	cairo_set_miter_limit(context, 2.0);

	cairo_set_source_rgb(context, 0.0, 0.3, 0.9);
	cairo_stroke_preserve(context);

	cairo_set_source_rgb(context, 0.9, 0.1, 0.8);
	cairo_fill(context);
}
Beispiel #13
0
void rendertext(cairo_t *cr) {
	PangoLayout *layout;
	layout = pango_cairo_create_layout(cr);

	pangotext(layout);

	cairo_new_path(cr);
	cairo_move_to(cr,0,0);
	cairo_set_line_width(cr,0.5);

	cairo_set_source_rgb(cr,0.0,0.0,1.0);

	pango_cairo_layout_path(cr,layout);

	cairo_stroke_preserve(cr);

	g_object_unref(layout);

}
Beispiel #14
0
static void annotation_txt(MF2UI *ui, RobTkDial * d, cairo_t *cr, const char *txt) {
	int tw, th;
	cairo_save(cr);
	PangoLayout * pl = pango_cairo_create_layout(cr);
	pango_layout_set_font_description(pl, ui->font[1]);
	pango_layout_set_text(pl, txt, -1);
	pango_layout_get_pixel_size(pl, &tw, &th);
	cairo_translate (cr, d->w_cx, d->w_height);
	cairo_translate (cr, -tw/2.0 - 0.5, -th);
	cairo_set_source_rgba (cr, .0, .0, .0, .7);
	rounded_rectangle(cr, -1, -1, tw+3, th+1, 3);
	cairo_fill(cr);
	CairoSetSouerceRGBA(c_wht);
	pango_cairo_layout_path(cr, pl);
	cairo_fill(cr);
	g_object_unref(pl);
	cairo_restore(cr);
	cairo_new_path(cr);
}
Beispiel #15
0
// Apply the labels to the map.
void
simplet_lithograph_apply(simplet_lithograph_t *litho, simplet_list_t *styles){
  simplet_listiter_t *iter = simplet_get_list_iter(litho->placements);
  placement_t *placement;
  cairo_save(litho->ctx);
  while((placement = (placement_t *) simplet_list_next(iter))){
    if(placement->placed == TRUE) continue;
    cairo_move_to(litho->ctx, placement->bounds->nw.x, placement->bounds->se.y);

    // Draw the placement
    pango_cairo_layout_path(litho->ctx, placement->layout);

    placement->placed = TRUE;
  }
  simplet_apply_styles(litho->ctx, styles, "text-stroke-weight", "text-stroke-color", "color",  NULL);

  // Apply and draw various outline options.
  cairo_restore(litho->ctx);
}
Beispiel #16
0
static PyObject *
pango_LayoutPath(PyObject *self, PyObject *args) {

	PycairoContext *context;
	cairo_t *ctx;
	void *LayoutObj;
	PangoLayout *layout;

	if (!PyArg_ParseTuple(args, "OO", &context, &LayoutObj)) {
		return NULL;
	}

	ctx = context->ctx;
	layout = PyCObject_AsVoidPtr(LayoutObj);

	pango_cairo_layout_path(ctx, layout);

	Py_INCREF(Py_None);
	return Py_None;
}
Beispiel #17
0
static void img_write_text(cairo_t* cr,
		const char *txt, const char *font,
		float x, float y, float ang)
{
	int tw, th;
	cairo_save(cr);
	PangoLayout * pl = pango_cairo_create_layout(cr);
	PangoFontDescription *desc = pango_font_description_from_string(font);
	pango_layout_set_font_description(pl, desc);
	pango_font_description_free(desc);
	pango_layout_set_text(pl, txt, -1);
	pango_layout_get_pixel_size(pl, &tw, &th);
	cairo_translate (cr, x, y);
	cairo_rotate (cr, ang);
	cairo_translate (cr, -tw/2.0, -th/2.0);
	pango_cairo_layout_path(cr, pl);
	cairo_fill(cr);
	g_object_unref(pl);
	cairo_restore(cr);
	cairo_new_path (cr);
}
Beispiel #18
0
static void br_cairo_draw_text(duc_graph *g, double x, double y, double size, char *text)
{
	struct cairo_backend_data *bd = g->backend_data;
	cairo_t *cr = bd->cr;

	char font[32];
	snprintf(font, sizeof font, "Arial, Sans, %.0f", size);
	PangoLayout *layout = pango_cairo_create_layout(cr);
	PangoFontDescription *desc = pango_font_description_from_string(font);

	pango_layout_set_alignment(layout, PANGO_ALIGN_CENTER);
	pango_layout_set_text(layout, text, -1);
	pango_layout_set_font_description(layout, desc);
	pango_font_description_free(desc);

	pango_cairo_update_layout(cr, layout);

	int w,h;
	pango_layout_get_size(layout, &w, &h);

	x -= ((double)w / PANGO_SCALE / 2);
	y -= ((double)h / PANGO_SCALE / 2);

	cairo_move_to(cr, x, y);
	pango_cairo_layout_path(cr, layout);
	g_object_unref(layout);
	
	/* light grey background */

	cairo_set_line_join (cr, CAIRO_LINE_JOIN_BEVEL);
	cairo_set_source_rgba(cr, 1, 1, 1, 0.6);
	cairo_set_line_width(cr, 3);
	cairo_stroke_preserve(cr);

	/* black text */

	cairo_set_source_rgb(cr, 0, 0, 0);
	cairo_set_line_width(cr, 1);
	cairo_fill(cr);
}
Beispiel #19
0
void draw_password_mask(void) {
    cairo_t *cr = cairo_create(lualock.pw_surface);
    cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR);
    cairo_paint(cr);
    cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
    draw_password_field(cr);

    PangoLayout *layout = pango_cairo_create_layout(cr);

    pango_layout_set_font_description(layout, lualock.style.font_desc);
    cairo_set_source_rgba(cr, lualock.style.r, lualock.style.g,
                          lualock.style.b, lualock.style.a);
    cairo_move_to(cr, lualock.style.off_x, lualock.style.off_y);
    gchar *password_mask = get_password_mask();
    pango_layout_set_text(layout, password_mask, -1);
    free(password_mask);
    pango_cairo_update_layout(cr, layout);
    pango_cairo_layout_path(cr, layout);
    cairo_fill(cr);
    g_object_unref(layout);
    cairo_destroy(cr);
}
Beispiel #20
0
static void
rsvg_cairo_clip_render_pango_layout (RsvgDrawingCtx * ctx, PangoLayout * layout, double x, double y)
{
    RsvgCairoClipRender *render = RSVG_CAIRO_CLIP_RENDER (ctx->render);
    RsvgCairoRender *cairo_render = &render->super;
    cairo_matrix_t affine;
    PangoGravity gravity = pango_context_get_gravity (pango_layout_get_context (layout));
    double rotation;

    affine = ctx->state->affine;
    rsvg_cairo_clip_apply_affine (render, &affine);

    rotation = pango_gravity_to_rotation (gravity);

    cairo_save (cairo_render->cr);
    cairo_move_to (cairo_render->cr, x, y);
    if (rotation != 0.)
        cairo_rotate (cairo_render->cr, -rotation);

    pango_cairo_update_layout (cairo_render->cr, layout);
    pango_cairo_layout_path (cairo_render->cr, layout);

    cairo_restore (cairo_render->cr);
}
Beispiel #21
0
void *dt_control_expose(void *voidptr)
{
  int width, height, pointerx, pointery;
  if(!darktable.gui->surface) return NULL;
  width = dt_cairo_image_surface_get_width(darktable.gui->surface);
  height = dt_cairo_image_surface_get_height(darktable.gui->surface);
  GtkWidget *widget = dt_ui_center(darktable.gui->ui);
  GdkDevice *device
      = gdk_device_manager_get_client_pointer(gdk_display_get_device_manager(gtk_widget_get_display(widget)));
  gdk_window_get_device_position(gtk_widget_get_window(widget), device, &pointerx, &pointery, NULL);

  // create a gtk-independent surface to draw on
  cairo_surface_t *cst = dt_cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height);
  cairo_t *cr = cairo_create(cst);

  // TODO: control_expose: only redraw the part not overlapped by temporary control panel show!
  //
  float tb = 8; // fmaxf(10, width/100.0);
  darktable.control->tabborder = tb;
  darktable.control->width = width;
  darktable.control->height = height;

  GdkRGBA color;
  GtkStyleContext *context = gtk_widget_get_style_context(widget);
  gboolean color_found = gtk_style_context_lookup_color (context, "bg_color", &color);
  if(!color_found)
  {
    color.red = 1.0;
    color.green = 0.0;
    color.blue = 0.0;
    color.alpha = 1.0;
  }
  gdk_cairo_set_source_rgba(cr, &color);

  cairo_set_line_width(cr, tb);
  cairo_rectangle(cr, tb / 2., tb / 2., width - tb, height - tb);
  cairo_stroke(cr);
  cairo_set_line_width(cr, 1.5);
  color_found = gtk_style_context_lookup_color (context, "really_dark_bg_color", &color);
  if(!color_found)
  {
    color.red = 1.0;
    color.green = 0.0;
    color.blue = 0.0;
    color.alpha = 1.0;
  }
  gdk_cairo_set_source_rgba(cr, &color);
  cairo_rectangle(cr, tb, tb, width - 2 * tb, height - 2 * tb);
  cairo_stroke(cr);

  cairo_save(cr);
  cairo_translate(cr, tb, tb);
  cairo_rectangle(cr, 0, 0, width - 2 * tb, height - 2 * tb);
  cairo_clip(cr);
  cairo_new_path(cr);
  // draw view
  dt_view_manager_expose(darktable.view_manager, cr, width - 2 * tb, height - 2 * tb, pointerx - tb,
                         pointery - tb);
  cairo_restore(cr);

  // draw log message, if any
  dt_pthread_mutex_lock(&darktable.control->log_mutex);
  if(darktable.control->log_ack != darktable.control->log_pos)
  {
    PangoRectangle ink;
    PangoLayout *layout;
    PangoFontDescription *desc = pango_font_description_copy_static(darktable.bauhaus->pango_font_desc);
    const float fontsize = DT_PIXEL_APPLY_DPI(14);
    pango_font_description_set_absolute_size(desc, fontsize * PANGO_SCALE);
    pango_font_description_set_weight(desc, PANGO_WEIGHT_BOLD);
    layout = pango_cairo_create_layout(cr);
    pango_layout_set_font_description(layout, desc);
    pango_layout_set_text(layout, darktable.control->log_message[darktable.control->log_ack], -1);
    pango_layout_get_pixel_extents(layout, &ink, NULL);
    const float pad = DT_PIXEL_APPLY_DPI(20.0f), xc = width / 2.0;
    const float yc = height * 0.85 + DT_PIXEL_APPLY_DPI(10), wd = pad + ink.width * .5f;
    float rad = DT_PIXEL_APPLY_DPI(14);
    cairo_set_line_width(cr, 1.);
    cairo_move_to(cr, xc - wd, yc + rad);
    for(int k = 0; k < 5; k++)
    {
      cairo_arc(cr, xc - wd, yc, rad, M_PI / 2.0, 3.0 / 2.0 * M_PI);
      cairo_line_to(cr, xc + wd, yc - rad);
      cairo_arc(cr, xc + wd, yc, rad, 3.0 * M_PI / 2.0, M_PI / 2.0);
      cairo_line_to(cr, xc - wd, yc + rad);
      if(k == 0)
      {
        color_found = gtk_style_context_lookup_color (context, "selected_bg_color", &color);
        if(!color_found)
        {
          color.red = 1.0;
          color.green = 0.0;
          color.blue = 0.0;
          color.alpha = 1.0;
        }
        gdk_cairo_set_source_rgba(cr, &color);
        cairo_fill_preserve(cr);
      }
      cairo_set_source_rgba(cr, 0., 0., 0., 1.0 / (1 + k));
      cairo_stroke(cr);
      rad += .5f;
    }
    color_found = gtk_style_context_lookup_color (context, "fg_color", &color);
    if(!color_found)
    {
      color.red = 1.0;
      color.green = 0.0;
      color.blue = 0.0;
      color.alpha = 1.0;
    }
    gdk_cairo_set_source_rgba(cr, &color);
    cairo_move_to(cr, xc - wd + .5f * pad, (yc + 1. / 3. * fontsize) - fontsize);
    pango_cairo_show_layout(cr, layout);
    pango_font_description_free(desc);
    g_object_unref(layout);
  }
  // draw busy indicator
  if(darktable.control->log_busy > 0)
  {
    PangoRectangle ink;
    PangoLayout *layout;
    PangoFontDescription *desc = pango_font_description_copy_static(darktable.bauhaus->pango_font_desc);
    const float fontsize = DT_PIXEL_APPLY_DPI(14);
    pango_font_description_set_absolute_size(desc, fontsize * PANGO_SCALE);
    pango_font_description_set_weight(desc, PANGO_WEIGHT_BOLD);
    layout = pango_cairo_create_layout(cr);
    pango_layout_set_font_description(layout, desc);
    pango_layout_set_text(layout, _("working.."), -1);
    pango_layout_get_pixel_extents(layout, &ink, NULL);
    const float xc = width / 2.0, yc = height * 0.85 - DT_PIXEL_APPLY_DPI(30), wd = ink.width * .5f;
    cairo_move_to(cr, xc - wd, yc + 1. / 3. * fontsize - fontsize);
    pango_cairo_layout_path(cr, layout);
    cairo_set_source_rgb(cr, 0.7, 0.7, 0.7);
    cairo_fill_preserve(cr);
    cairo_set_line_width(cr, 0.7);
    cairo_set_source_rgb(cr, 0.3, 0.3, 0.3);
    cairo_stroke(cr);
    pango_font_description_free(desc);
    g_object_unref(layout);
  }
  dt_pthread_mutex_unlock(&darktable.control->log_mutex);

  cairo_destroy(cr);

  cairo_t *cr_pixmap = cairo_create(darktable.gui->surface);
  cairo_set_source_surface(cr_pixmap, cst, 0, 0);
  cairo_paint(cr_pixmap);
  cairo_destroy(cr_pixmap);

  cairo_surface_destroy(cst);
  return NULL;
}
Beispiel #22
0
static gboolean _lib_histogram_draw_callback(GtkWidget *widget, cairo_t *crf, gpointer user_data)
{
  dt_lib_module_t *self = (dt_lib_module_t *)user_data;
  dt_lib_histogram_t *d = (dt_lib_histogram_t *)self->data;

  dt_develop_t *dev = darktable.develop;
  uint32_t *hist = dev->histogram;
  float hist_max = dev->histogram_type == DT_DEV_HISTOGRAM_LINEAR ? dev->histogram_max
                                                                  : logf(1.0 + dev->histogram_max);
  const int inset = DT_HIST_INSET;
  GtkAllocation allocation;
  gtk_widget_get_allocation(widget, &allocation);
  int width = allocation.width, height = allocation.height;
  cairo_surface_t *cst = dt_cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height);
  cairo_t *cr = cairo_create(cst);

  gtk_render_background(gtk_widget_get_style_context(widget), cr, 0, 0, allocation.width, allocation.height);

  cairo_translate(cr, 4 * inset, inset);
  width -= 2 * 4 * inset;
  height -= 2 * inset;

  if(d->mode_x == 0)
  {
    d->color_w = 0.06 * width;
    d->button_spacing = 0.01 * width;
    d->button_h = 0.06 * width;
    d->button_y = d->button_spacing;
    d->mode_w = d->color_w;
    d->mode_x = width - 3 * (d->color_w + d->button_spacing) - (d->mode_w + d->button_spacing);
    d->red_x = width - 3 * (d->color_w + d->button_spacing);
    d->green_x = width - 2 * (d->color_w + d->button_spacing);
    d->blue_x = width - (d->color_w + d->button_spacing);
  }

  // TODO: probably this should move to the configure-event callback! That would be future proof if we ever
  // (again) allow to resize the side panels.
  const gint stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width);

  // this code assumes that the first expose comes before the first (preview) pipe is processed and that the
  // size of the widget doesn't change!
  if(dev->histogram_waveform_width == 0)
  {
    dev->histogram_waveform = (uint32_t *)calloc(height * stride / 4, sizeof(uint32_t));
    dev->histogram_waveform_stride = stride;
    dev->histogram_waveform_height = height;
    dev->histogram_waveform_width = width;
    //     return TRUE; // there are enough expose events following ...
  }

#if 1
  // draw shadow around
  float alpha = 1.0f;
  cairo_set_line_width(cr, 0.2);
  for(int k = 0; k < inset; k++)
  {
    cairo_rectangle(cr, -k, -k, width + 2 * k, height + 2 * k);
    cairo_set_source_rgba(cr, 0, 0, 0, alpha);
    alpha *= 0.5f;
    cairo_fill(cr);
  }
  cairo_set_line_width(cr, 1.0);
#else
  cairo_set_line_width(cr, 1.0);
  cairo_set_source_rgb(cr, .1, .1, .1);
  cairo_rectangle(cr, 0, 0, width, height);
  cairo_stroke(cr);
#endif

  cairo_rectangle(cr, 0, 0, width, height);
  cairo_clip(cr);

  cairo_set_source_rgb(cr, .3, .3, .3);
  cairo_rectangle(cr, 0, 0, width, height);
  cairo_fill(cr);
  if(d->highlight == 1)
  {
    cairo_set_source_rgb(cr, .5, .5, .5);
    cairo_rectangle(cr, 0, 0, .2 * width, height);
    cairo_fill(cr);
  }
  else if(d->highlight == 2)
  {
    cairo_set_source_rgb(cr, .5, .5, .5);
    cairo_rectangle(cr, 0.2 * width, 0, width, height);
    cairo_fill(cr);
  }

  // draw grid
  cairo_set_line_width(cr, .4);
  cairo_set_source_rgb(cr, .1, .1, .1);
  if(dev->histogram_type == DT_DEV_HISTOGRAM_WAVEFORM)
    dt_draw_waveform_lines(cr, 0, 0, width, height);
  else
    dt_draw_grid(cr, 4, 0, 0, width, height);

  if(hist_max > 0.0f)
  {
    cairo_save(cr);
    if(dev->histogram_type == DT_DEV_HISTOGRAM_WAVEFORM)
    {
      // make the color channel selector work:
      uint8_t *buf = (uint8_t *)malloc(sizeof(uint8_t) * height * stride);
      uint8_t mask[3] = { d->blue, d->green, d->red };
      memcpy(buf, dev->histogram_waveform, sizeof(uint8_t) * height * stride);
      for(int y = 0; y < height; y++)
        for(int x = 0; x < width; x++)
          for(int k = 0; k < 3; k++)
          {
            buf[y * stride + x * 4 + k] *= mask[k];
          }

      cairo_surface_t *source
          = cairo_image_surface_create_for_data(buf, CAIRO_FORMAT_ARGB32, width, height, stride);

      cairo_set_source_surface(cr, source, 0.0, 0.0);
      cairo_set_operator(cr, CAIRO_OPERATOR_ADD);
      cairo_paint(cr);
      cairo_surface_destroy(source);
      free(buf);
    }
    else
    {
      // cairo_set_antialias(cr, CAIRO_ANTIALIAS_NONE);
      cairo_translate(cr, 0, height);
      cairo_scale(cr, width / 63.0, -(height - 10) / hist_max);
      cairo_set_operator(cr, CAIRO_OPERATOR_ADD);
      // cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
      cairo_set_line_width(cr, 1.);
      if(d->red)
      {
        cairo_set_source_rgba(cr, 1., 0., 0., 0.2);
        dt_draw_histogram_8(cr, hist, 0, dev->histogram_type == DT_DEV_HISTOGRAM_LINEAR);
      }
      if(d->green)
      {
        cairo_set_source_rgba(cr, 0., 1., 0., 0.2);
        dt_draw_histogram_8(cr, hist, 1, dev->histogram_type == DT_DEV_HISTOGRAM_LINEAR);
      }
      if(d->blue)
      {
        cairo_set_source_rgba(cr, 0., 0., 1., 0.2);
        dt_draw_histogram_8(cr, hist, 2, dev->histogram_type == DT_DEV_HISTOGRAM_LINEAR);
      }
      cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
      // cairo_set_antialias(cr, CAIRO_ANTIALIAS_DEFAULT);
    }
    cairo_restore(cr);
  }

  cairo_set_source_rgb(cr, .25, .25, .25);
  cairo_set_line_join(cr, CAIRO_LINE_JOIN_ROUND);
  PangoLayout *layout;
  PangoRectangle ink;
  PangoFontDescription *desc = pango_font_description_copy_static(darktable.bauhaus->pango_font_desc);
  pango_font_description_set_weight(desc, PANGO_WEIGHT_BOLD);
  layout = pango_cairo_create_layout(cr);
  pango_font_description_set_absolute_size(desc, .1 * height * PANGO_SCALE);
  pango_layout_set_font_description(layout, desc);

  char exifline[50];
  dt_image_print_exif(&dev->image_storage, exifline, 50);
  pango_layout_set_text(layout, exifline, -1);
  pango_layout_get_pixel_extents(layout, &ink, NULL);
  cairo_move_to(cr, .02 * width, .98 * height - ink.height - ink.y);
  cairo_save(cr);
  cairo_set_line_width(cr, DT_PIXEL_APPLY_DPI(2.0));
  cairo_set_source_rgba(cr, 1, 1, 1, 0.3);
  pango_cairo_layout_path(cr, layout);
  cairo_stroke_preserve(cr);
  cairo_set_source_rgb(cr, .25, .25, .25);
  cairo_fill(cr);
  cairo_restore(cr);

  // buttons to control the display of the histogram: linear/log, r, g, b
  if(d->highlight != 0)
  {
    _draw_mode_toggle(cr, d->mode_x, d->button_y, d->mode_w, d->button_h, dev->histogram_type);
    cairo_set_source_rgba(cr, 1.0, 0.0, 0.0, 0.4);
    _draw_color_toggle(cr, d->red_x, d->button_y, d->color_w, d->button_h, d->red);
    cairo_set_source_rgba(cr, 0.0, 1.0, 0.0, 0.4);
    _draw_color_toggle(cr, d->green_x, d->button_y, d->color_w, d->button_h, d->green);
    cairo_set_source_rgba(cr, 0.0, 0.0, 1.0, 0.4);
    _draw_color_toggle(cr, d->blue_x, d->button_y, d->color_w, d->button_h, d->blue);
  }

  cairo_destroy(cr);
  cairo_set_source_surface(crf, cst, 0, 0);
  cairo_paint(crf);
  cairo_surface_destroy(cst);
  pango_font_description_free(desc);
  g_object_unref(layout);
  return TRUE;
}
Beispiel #23
0
void render_glyph(
	cairo_t* cr,
	PangoFontDescription* font_desc,
	PangoFont* font,
	const guint code_point,
	const size_t cell_x,
	const size_t cell_y,
	const size_t cell_size,
	const double tex_size,
	const int ascent,
	const int descent,
	std::ostream& bgm_out
)
{
	PangoLayout *layout = pango_cairo_create_layout(cr);

	char str[6] = {'\0'};
	size_t len = 0;
	oglplus::aux::ConvertCodePointToUTF8(code_point, str, len);

	pango_layout_set_font_description(layout, font_desc);
	pango_layout_set_text(layout, str, len);

	const int baseline = pango_layout_get_baseline(layout);
	const double inv_ps = 1.0 / double(PANGO_SCALE);
	const double font_size = ascent+descent;

	PangoRectangle ink_rect, log_rect;
	pango_layout_get_extents(
		layout,
		&ink_rect,
		&log_rect
	);

	// code point number
	bgm_out << code_point << std::endl;
	// hex representation of the number
	bgm_out	<< std::hex
		<< "0x"
		<< code_point
		<< std::dec
		<< std::endl;
	// the utf-8 sequence
	bgm_out << "'" << str << "'" << std::endl;
	//
	// vertex[0] logical rectangle metrics
	//
	// Left bearing (x)
	bgm_out << PANGO_LBEARING(log_rect)/font_size << std::endl;
	// Right bearing (x+width)
	bgm_out << PANGO_RBEARING(log_rect)/font_size << std::endl;
	// Ascent
	bgm_out << (baseline-log_rect.y)/font_size << std::endl;
	// Descent
	bgm_out << (log_rect.height+log_rect.y-baseline)/font_size << std::endl;
	//
	// vertex[1] ink rectangle metrics
	//
	// Left bearing (x)
	bgm_out << PANGO_LBEARING(ink_rect)/font_size << std::endl;
	// Right bearing (x+width)
	bgm_out << PANGO_RBEARING(ink_rect)/font_size << std::endl;
	// Ascent
	bgm_out << (baseline-ink_rect.y)/font_size << std::endl;
	// Descent
	bgm_out << (ink_rect.y+ink_rect.height-baseline)/font_size << std::endl;
	//
	// vertex[2] texture coordinates
	//
	// Origin X
	bgm_out << (cell_x*cell_size+ink_rect.x*inv_ps)/tex_size << std::endl;
	// Origin Y
	bgm_out << 1.0-(cell_y*cell_size+baseline*inv_ps)/tex_size << std::endl;
	// Width
	bgm_out << ((ink_rect.width)*inv_ps)/tex_size << std::endl;
	// Height
	bgm_out << ((ink_rect.height)*inv_ps)/tex_size << std::endl;


	// separating newline
	bgm_out << std::endl;

	cairo_new_path(cr);
	cairo_move_to(cr, cell_x*cell_size, cell_y*cell_size);
	cairo_set_line_width(cr, 0.5);

	pango_cairo_update_layout(cr, layout);
	pango_cairo_layout_path(cr, layout);
	cairo_fill(cr);

	g_object_unref(layout);
}
Beispiel #24
0
static gboolean
video_area_draw_cb (GtkWidget *widget,
		    cairo_t   *cr,
		    gpointer   user_data)
{
	GthMediaViewerPage *self = user_data;
	GtkAllocation       allocation;
	GtkStyleContext    *style_context;

	if (self->priv->xwin_assigned && self->priv->has_video)
		return FALSE;

	gtk_widget_get_allocation (widget, &allocation);
	style_context = gtk_widget_get_style_context (widget);

	if (self->priv->icon == NULL) {
		char  *type;
		GIcon *icon;
		int    size;

		type = NULL;
		if (self->priv->file_data != NULL)
			type = g_content_type_from_mime_type (gth_file_data_get_mime_type (self->priv->file_data));
		if (type == NULL)
			type = g_content_type_from_mime_type ("text/plain");
		icon = g_content_type_get_icon (type);
		size = allocation.width;
		if (size > allocation.height)
			size = allocation.height;
		size = size / 3;
		self->priv->icon = _g_icon_get_pixbuf (icon, size, _gtk_widget_get_icon_theme (widget));

		g_object_unref (icon);
		g_free (type);
	}

	cairo_set_source_rgb (cr, 0.0, 0.0, 0.0);
	cairo_rectangle (cr, 0, 0, allocation.width, allocation.height);
	cairo_fill (cr);

	if (self->priv->icon != NULL) {
		int                   icon_w, icon_h;
		int                   text_w;
		int                   icon_x, icon_y;
		PangoRectangle        logical_rect;
		int                   x, y;
		PangoFontDescription *font;

		icon_w = gdk_pixbuf_get_width (self->priv->icon);
		icon_h = gdk_pixbuf_get_height (self->priv->icon);

		text_w = (icon_w * 3 / 2);
		pango_layout_set_width (self->priv->caption_layout, PANGO_SCALE * text_w);
		pango_layout_get_extents (self->priv->caption_layout, NULL, &logical_rect);

		icon_x = (allocation.width - icon_w) / 2;
		x = (allocation.width - text_w) / 2;

		icon_y = (allocation.height - (icon_h + PANGO_PIXELS (logical_rect.height))) / 2;
		y = icon_y + icon_h;

		gdk_cairo_set_source_pixbuf (cr, self->priv->icon, icon_x, icon_y);
		cairo_rectangle (cr, icon_x, icon_y, icon_w, icon_h);
		cairo_fill (cr);

		cairo_move_to (cr, x, y);
		gtk_style_context_get (style_context, gtk_widget_get_state_flags (widget), "font", &font, NULL);
		pango_layout_set_font_description (self->priv->caption_layout, font);
		pango_cairo_layout_path (cr, self->priv->caption_layout);
		cairo_set_source_rgb (cr, 1.0, 1.0, 1.0);
		cairo_fill (cr);
	}

	return TRUE;
}
Beispiel #25
0
static void write_text_full (
		cairo_t* cr,
		const char *txt,
		PangoFontDescription *font,
		const float x, const float y,
		const float ang, const int align,
		const float * const col) {
	int tw, th;
	cairo_save(cr);

	PangoLayout * pl = pango_cairo_create_layout(cr);
	pango_layout_set_font_description(pl, font);
	if (strncmp(txt, "<markup>", 8)) {
		pango_layout_set_text(pl, txt, -1);
	} else {
		pango_layout_set_markup(pl, txt, -1);
	}
	pango_layout_get_pixel_size(pl, &tw, &th);
	cairo_translate (cr, rintf(x), rintf(y));
	if (ang != 0) { cairo_rotate (cr, ang); }
	switch(abs(align)) {
		case 1:
			cairo_translate (cr, -tw, ceil(th/-2.0));
			pango_layout_set_alignment (pl, PANGO_ALIGN_RIGHT);
			break;
		case 2:
			cairo_translate (cr, ceil(tw/-2.0), ceil(th/-2.0));
			pango_layout_set_alignment (pl, PANGO_ALIGN_CENTER);
			break;
		case 3:
			cairo_translate (cr, 0, ceil(th/-2.0));
			pango_layout_set_alignment (pl, PANGO_ALIGN_LEFT);
			break;
		case 4:
			cairo_translate (cr, -tw, -th);
			pango_layout_set_alignment (pl, PANGO_ALIGN_RIGHT);
			break;
		case 5:
			cairo_translate (cr, ceil(tw/-2.0), -th);
			pango_layout_set_alignment (pl, PANGO_ALIGN_CENTER);
			break;
		case 6:
			cairo_translate (cr, 0, -th);
			pango_layout_set_alignment (pl, PANGO_ALIGN_LEFT);
			break;
		case 7:
			cairo_translate (cr, -tw, 0);
			pango_layout_set_alignment (pl, PANGO_ALIGN_RIGHT);
			break;
		case 8:
			cairo_translate (cr, ceil(tw/-2.0), 0);
			pango_layout_set_alignment (pl, PANGO_ALIGN_CENTER);
			break;
		case 9:
			cairo_translate (cr, 0, 0);
			pango_layout_set_alignment (pl, PANGO_ALIGN_LEFT);
			break;
		default:
			break;
	}
	if (align < 0) {
		cairo_set_source_rgba (cr, .0, .0, .0, .5);
		cairo_rectangle (cr, 0, 0, tw, th);
		cairo_fill (cr);
	}
#if 1
	cairo_set_source_rgba (cr, col[0], col[1], col[2], col[3]);
	pango_cairo_show_layout(cr, pl);
#else
	cairo_set_source_rgba (cr, col[0], col[1], col[2], col[3]);
	pango_cairo_layout_path(cr, pl);
	cairo_fill(cr);
#endif
	g_object_unref(pl);
	cairo_restore(cr);
	cairo_new_path (cr);
}
Beispiel #26
0
gboolean	ly_3lrc_desktop_on_expose_cb	(GtkWidget * widget, cairo_t *cr, gpointer data)
{
	gchar desktop_font[1024]="Sans Regular 25";
	ly_reg_get("3lrc_desktop_font", "%1024[^\n]", desktop_font);

	gchar path[1024];
	g_snprintf(path,sizeof(path),"%sicon/null.png",LY_GLB_PROG_UIXDIR);
	if(!desktop_bg)
		desktop_bg=cairo_image_surface_create_from_png(path);

	cairo_set_source_surface(cr, desktop_bg, 0, 0);
	cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
	cairo_paint(cr);
	
	int width;
	int height;
	width = gtk_widget_get_allocated_width (widget);
	height = gtk_widget_get_allocated_height (widget);
	
	int x=0;
	int y=height;
	
	//鼠标进入
	if(flag_notify)
	{
		//填充圆角矩形拖动区域
		cairo_set_source_rgba(cr,0,0,0,0.3);
		cairo_move_to (cr, 0 + 5, 0);
		cairo_line_to (cr, 0 + width - 5, 0);
		cairo_move_to (cr, 0 + width, 0 + 5);
		cairo_line_to (cr, 0 + width, 0 + height - 5);
		cairo_move_to (cr, 0 + width - 5, 0 + height);
		cairo_line_to (cr, 0 + 5, 0 + height);
		cairo_move_to (cr, 0, 0 + height - 5);
		cairo_line_to (cr, 0, 0 + 5);
		cairo_arc (cr, 0 + 5, 0 + 5, 5, M_PI, 3 * M_PI / 2.0);
		cairo_arc (cr, 0 + width - 5, 0 + 5, 5, 3 * M_PI / 2, 2 * M_PI);
		cairo_arc (cr, 0 + width - 5, 0 + height - 5, 5, 0, M_PI / 2);
		cairo_arc (cr, 0 + 5, 0 + height - 5, 5, M_PI / 2, M_PI);
		cairo_fill(cr);
	}
	
	if(ly_lrc_get_length()>0)
	{
		//计算占空比
		gint64 t1=0;
		gint64 t2=0;
		
		LyMdhMetadata *md=NULL;
		md=ly_pqm_get_current_md();
		if(!md)
			return FALSE;
		if(ly_lrc_get_index()+1<ly_lrc_get_length())
			t1=(ly_lrc_get_array()[ly_lrc_get_index()+1])->time-(ly_lrc_get_array()[ly_lrc_get_index()])->time;
		else
			t1=ly_mdh_time_str2int(md->duration)-ly_mdh_time_str2int(md->start)-(ly_lrc_get_array()[ly_lrc_get_index()])->time;
		
		t2=ly_aud_get_position_abs()-ly_mdh_time_str2int(md->start)-(ly_lrc_get_array()[ly_lrc_get_index()])->time;
		if(t1!=0)
		{
			x=(int)((t2/(gdouble)t1)*pos_layout[X]);
		}
		
		//画歌词
		cairo_set_source_rgb(cr,0,0,0);
		
		//确定起始点
		if((x>=width/2)&&(pos_layout[X]>width)&&(width<(pos_layout[X]-x)*2))
		{
			cairo_move_to(cr, 0-(x-width/2), 5);
			x=width/2;
		}
		else if((x>=width/2)&&(pos_layout[X]>width)&&(width>=(pos_layout[X]-x)*2))
			cairo_move_to(cr, 0-(pos_layout[X]-width), 5);
		else
			cairo_move_to(cr, 0, 5);
		
		PangoLayout *layout;
		PangoFontDescription *desc;
		layout = pango_cairo_create_layout (cr);
		
		pango_layout_set_text(layout, ly_lrc_get_array()[ly_lrc_get_index()]->text, -1);
		desc = pango_font_description_from_string (desktop_font);
		pango_layout_set_font_description (layout, desc);
		pango_font_description_free (desc);
		
		
		pango_layout_get_size(layout,&pos_layout[X],&pos_layout[Y]);
		pos_layout[X]=pos_layout[X]/1000;
		
		pango_cairo_update_layout (cr, layout);
		pango_cairo_layout_path (cr, layout);
		cairo_clip(cr);
		g_object_unref (layout);
		
		//画背景条
		cairo_pattern_t *pat;
		pat = cairo_pattern_create_linear (0, 0,10.0, 150);
		cairo_pattern_add_color_stop_rgb (pat, 0.1, 65535/65535.0, 10449/65535.0, 0/65535.0);
		cairo_pattern_add_color_stop_rgb (pat, 0.5, 65535/65535.0, 61062/65535.0, 0/65535.0);
		cairo_pattern_add_color_stop_rgb (pat, 0.9, 65535/65535.0, 10449/65535.0, 0/65535.0);
		//画矩形
		if((x>=width/2)&&(pos_layout[X]>width)&&(width<(pos_layout[X]-x)*2))
			cairo_rectangle (cr, 0, 0, width/2, y);
		else if((x>=width/2)&&(pos_layout[X]>width)&&(width>=(pos_layout[X]-x)*2))
			cairo_rectangle (cr, 0, 0, width-(pos_layout[X]-x), y);
		else
			cairo_rectangle (cr, 0, 0, x, y);
		cairo_set_source (cr, pat);
		cairo_fill(cr);
		cairo_pattern_destroy (pat);
		pat = cairo_pattern_create_linear (0, 0,10.0, 150);
		cairo_pattern_add_color_stop_rgb (pat, 0.1, 19532/65535.0, 65535/65535.0, 65535/65535.0);
		cairo_pattern_add_color_stop_rgb (pat, 0.5, 5539/65535.0, 0/65535.0, 65535/65535.0);
		cairo_pattern_add_color_stop_rgb (pat, 0.9, 19532/65535.0, 65535/65535.0, 65535/65535.0);
		//画矩形
		if((x>=width/2)&&(pos_layout[X]>width)&&(width<(pos_layout[X]-x)*2))
			cairo_rectangle (cr, width/2, 0, width-(width/2), y);
		else if((x>=width/2)&&(pos_layout[X]>width)&&(width>=(pos_layout[X]-x)*2))
			cairo_rectangle (cr, width-(pos_layout[X]-x), 0, pos_layout[X]-x, y);
		else
			cairo_rectangle (cr, x, 0, width-x, y);
		cairo_set_source (cr, pat);
		cairo_fill(cr);
		cairo_pattern_destroy (pat);
	}
	
	int lrc_desktop=1;
	int lrc_desktop_fix=0;
	if(!ly_reg_get("3lrc_desktop_state", "%d:%d", &lrc_desktop, &lrc_desktop_fix))
	{
		ly_reg_set("3lrc_desktop_state", "%d:%d", lrc_desktop, lrc_desktop_fix);
	}
	if(lrc_desktop_fix>0)
		gtk_widget_set_sensitive(widget,FALSE);
	else
		gtk_widget_set_sensitive(widget,TRUE);
	cairo_region_t *region;
	if(!(lrc_desktop_fix))
	{
		cairo_rectangle_int_t rect;
		rect.x=rect.y=0;
		rect.width=width;
		rect.height=height;
		region=cairo_region_create_rectangle(&rect);
	}
	else
	{
		region=cairo_region_create();
	}
	gdk_window_input_shape_combine_region (gtk_widget_get_window(widget), region, 0, 0);
	cairo_region_destroy (region);
	
	return FALSE;
}
Beispiel #27
0
gboolean
text_to_path (const Text *text, GArray *points)
{
  cairo_t *cr;
  cairo_surface_t *surface;
  PangoLayout *layout;
  PangoRectangle ink_rect;
  char *str;
  gboolean ret = FALSE;

  if (!PANGO_IS_CAIRO_FONT_MAP (pango_context_get_font_map (dia_font_get_context())))
    return FALSE;

  layout = pango_layout_new(dia_font_get_context());
  pango_layout_set_font_description (layout, dia_font_get_description (text->font));
  pango_layout_set_indent (layout, 0);
  pango_layout_set_justify (layout, FALSE);
  pango_layout_set_alignment (layout, 
			      text->alignment == ALIGN_LEFT ? PANGO_ALIGN_LEFT :
			      text->alignment == ALIGN_RIGHT ? PANGO_ALIGN_RIGHT : PANGO_ALIGN_CENTER);

  str = text_get_string_copy (text);
  pango_layout_set_text (layout, str, -1);
  g_free (str);

  pango_layout_get_extents (layout, &ink_rect, NULL);
  /* any surface should do - this one is always available */
  surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
					ink_rect.width / PANGO_SCALE, ink_rect.height / PANGO_SCALE);
  cr = cairo_create (surface);
  cairo_surface_destroy (surface);

  pango_cairo_layout_path (cr, layout);

  /* convert the path */
  if (cairo_status (cr) == CAIRO_STATUS_SUCCESS)
  {
    cairo_path_t *path;
    int i;

    path = cairo_copy_path (cr);

    for (i=0; i < path->num_data; i += path->data[i].header.length) {
      cairo_path_data_t *data = &path->data[i];
      BezPoint bp;

      switch (data->header.type) {
      case CAIRO_PATH_MOVE_TO :
	bp.type = BEZ_MOVE_TO;
	bp.p1.x = data[1].point.x; bp.p1.y = data[1].point.y;
	break;
      case CAIRO_PATH_LINE_TO :
        bp.type = BEZ_LINE_TO;
	bp.p1.x = data[1].point.x; bp.p1.y = data[1].point.y;
	break;
      case CAIRO_PATH_CURVE_TO :
        bp.type = BEZ_CURVE_TO;
	bp.p1.x = data[1].point.x; bp.p1.y = data[1].point.y;
	bp.p2.x = data[2].point.x; bp.p2.y = data[2].point.y;
	bp.p3.x = data[3].point.x; bp.p3.y = data[3].point.y;
	break;
      case CAIRO_PATH_CLOSE_PATH :
        /* can't do anything */
      default :
        continue;
      }
      g_array_append_val (points, bp);
    }
    ret = (path->status == CAIRO_STATUS_SUCCESS);
    cairo_path_destroy (path);
  }
  /* finally scale it ? */

  /* clean up */
  g_object_unref (layout);
  cairo_destroy (cr);

  return ret;
}
static GdkPixbuf *
create_gallery (ThumbApp *app)
{
	GdkPixbuf *screenshot, *pixbuf = NULL;
	cairo_t *cr;
	cairo_surface_t *surface;
	PangoLayout *layout;
	PangoFontDescription *font_desc;
	gint64 stream_length, screenshot_interval, pos;
	guint columns = 3, rows, current_column, current_row, x, y;
	gint screenshot_width = 0, screenshot_height = 0, x_padding = 0, y_padding = 0;
	gfloat scale = 1.0;
	gchar *header_text, *duration_text, *filename;

	/* Calculate how many screenshots we're going to take */
	stream_length = app->duration;

	/* As a default, we have one screenshot per minute of stream,
	 * but adjusted so we don't have any gaps in the resulting gallery. */
	if (gallery == 0) {
		gallery = stream_length / 60000;

		while (gallery % 3 != 0 &&
		       gallery % 4 != 0 &&
		       gallery % 5 != 0) {
			gallery++;
		}
	}

	if (gallery < GALLERY_MIN)
		gallery = GALLERY_MIN;
	if (gallery > GALLERY_MAX)
		gallery = GALLERY_MAX;
	screenshot_interval = stream_length / gallery;

	/* Put a lower bound on the screenshot interval so we can't enter an infinite loop below */
	if (screenshot_interval == 0)
		screenshot_interval = 1;

	PROGRESS_DEBUG ("Producing gallery of %u screenshots, taken at %" G_GINT64_FORMAT " millisecond intervals throughout a %" G_GINT64_FORMAT " millisecond-long stream.",
			gallery, screenshot_interval, stream_length);

	/* Calculate how to arrange the screenshots so we don't get ones orphaned on the last row.
	 * At this point, only deal with arrangements of 3, 4 or 5 columns. */
	y = G_MAXUINT;
	for (x = 3; x <= 5; x++) {
		if (gallery % x == 0 || x - gallery % x < y) {
			y = x - gallery % x;
			columns = x;

			/* Have we found an optimal solution already? */
			if (y == x)
				break;
		}
	}

	rows = ceil ((gfloat) gallery / (gfloat) columns);

	PROGRESS_DEBUG ("Outputting as %u rows and %u columns.", rows, columns);

	/* Take the screenshots and composite them into a pixbuf */
	current_column = current_row = x = y = 0;
	for (pos = screenshot_interval; pos <= stream_length; pos += screenshot_interval) {
		if (pos == stream_length)
			screenshot = capture_frame_at_time (app, pos - 1);
		else
			screenshot = capture_frame_at_time (app, pos);

		if (pixbuf == NULL) {
			screenshot_width = gdk_pixbuf_get_width (screenshot);
			screenshot_height = gdk_pixbuf_get_height (screenshot);

			/* Calculate a scaling factor so that screenshot_width -> output_size */
			scale = (float) output_size / (float) screenshot_width;

			x_padding = x = MAX (output_size * 0.05, 1);
			y_padding = y = MAX (scale * screenshot_height * 0.05, 1);

			PROGRESS_DEBUG ("Scaling each screenshot by %f.", scale);

			/* Create our massive pixbuf */
			pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8,
						 columns * output_size + (columns + 1) * x_padding,
						 (guint) (rows * scale * screenshot_height + (rows + 1) * y_padding));
			gdk_pixbuf_fill (pixbuf, 0x000000ff);

			PROGRESS_DEBUG ("Created output pixbuf (%ux%u).", gdk_pixbuf_get_width (pixbuf), gdk_pixbuf_get_height (pixbuf));
		}

		/* Composite the screenshot into our gallery */
		gdk_pixbuf_composite (screenshot, pixbuf,
				      x, y, output_size, scale * screenshot_height,
				      (gdouble) x, (gdouble) y, scale, scale,
				      GDK_INTERP_BILINEAR, 255);
		g_object_unref (screenshot);

		PROGRESS_DEBUG ("Composited screenshot from %" G_GINT64_FORMAT " milliseconds (address %u) at (%u,%u).",
				pos, GPOINTER_TO_UINT (screenshot), x, y);

		/* We print progress in the range 10% (MIN_PROGRESS) to 50% (MAX_PROGRESS - MIN_PROGRESS) / 2.0 */
		PRINT_PROGRESS (MIN_PROGRESS + (current_row * columns + current_column) * (((MAX_PROGRESS - MIN_PROGRESS) / gallery) / 2.0));

		current_column = (current_column + 1) % columns;
		x += output_size + x_padding;
		if (current_column == 0) {
			x = x_padding;
			y += scale * screenshot_height + y_padding;
			current_row++;
		}
	}

	PROGRESS_DEBUG ("Converting pixbuf to a Cairo surface.");

	/* Load the pixbuf into a Cairo surface and overlay the text. The height is the height of
	 * the gallery plus the necessary height for 3 lines of header (at ~18px each), plus some
	 * extra padding. */
	surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, gdk_pixbuf_get_width (pixbuf),
					      gdk_pixbuf_get_height (pixbuf) + GALLERY_HEADER_HEIGHT + y_padding);
	cr = cairo_create (surface);
	cairo_surface_destroy (surface);

	/* First, copy across the gallery pixbuf */
	gdk_cairo_set_source_pixbuf (cr, pixbuf, 0.0, GALLERY_HEADER_HEIGHT + y_padding);
	cairo_rectangle (cr, 0.0, GALLERY_HEADER_HEIGHT + y_padding, gdk_pixbuf_get_width (pixbuf), gdk_pixbuf_get_height (pixbuf));
	cairo_fill (cr);
	g_object_unref (pixbuf);

	/* Build the header information */
	duration_text = xplayer_time_to_string (stream_length);
	filename = NULL;
	if (strstr (app->input, "://")) {
		char *local;
		local = g_filename_from_uri (app->input, NULL, NULL);
		filename = g_path_get_basename (local);
		g_free (local);
	}
	if (filename == NULL)
		filename = g_path_get_basename (app->input);

	/* Translators: The first string is "Filename" (as translated); the second is an actual filename.
			The third string is "Resolution" (as translated); the fourth and fifth are screenshot height and width, respectively.
			The sixth string is "Duration" (as translated); the seventh is the movie duration in words. */
	header_text = g_markup_printf_escaped (_("<b>%s</b>: %s\n<b>%s</b>: %d\303\227%d\n<b>%s</b>: %s"),
					       _("Filename"),
					       filename,
					       _("Resolution"),
					       screenshot_width,
					       screenshot_height,
					       _("Duration"),
					       duration_text);
	g_free (duration_text);
	g_free (filename);

	PROGRESS_DEBUG ("Writing header text with Pango.");

	/* Write out some header information */
	layout = pango_cairo_create_layout (cr);
	font_desc = pango_font_description_from_string ("Sans 18px");
	pango_layout_set_font_description (layout, font_desc);
	pango_font_description_free (font_desc);

	pango_layout_set_markup (layout, header_text, -1);
	g_free (header_text);

	cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); /* white */
	cairo_move_to (cr, (gdouble) x_padding, (gdouble) y_padding);
	pango_cairo_show_layout (cr, layout);

	/* Go through each screenshot and write its timestamp */
	current_column = current_row = 0;
	x = x_padding + output_size;
	y = y_padding * 2 + GALLERY_HEADER_HEIGHT + scale * screenshot_height;

	font_desc = pango_font_description_from_string ("Sans 10px");
	pango_layout_set_font_description (layout, font_desc);
	pango_font_description_free (font_desc);

	PROGRESS_DEBUG ("Writing screenshot timestamps with Pango.");

	for (pos = screenshot_interval; pos <= stream_length; pos += screenshot_interval) {
		gchar *timestamp_text;
		gint layout_width, layout_height;

		timestamp_text = xplayer_time_to_string (pos);

		pango_layout_set_text (layout, timestamp_text, -1);
		pango_layout_get_pixel_size (layout, &layout_width, &layout_height);

		/* Display the timestamp in the bottom-right corner of the current screenshot */
		cairo_move_to (cr, x - layout_width - 0.02 * output_size, y - layout_height - 0.02 * scale * screenshot_height);

		/* We have to stroke the text so it's visible against screenshots of the same
		 * foreground color. */
		pango_cairo_layout_path (cr, layout);
		cairo_set_source_rgb (cr, 0.0, 0.0, 0.0); /* black */
		cairo_stroke_preserve (cr);
		cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); /* white */
		cairo_fill (cr);

		PROGRESS_DEBUG ("Writing timestamp \"%s\" at (%f,%f).", timestamp_text,
				x - layout_width - 0.02 * output_size,
				y - layout_height - 0.02 * scale * screenshot_height);

		/* We print progress in the range 50% (MAX_PROGRESS - MIN_PROGRESS) / 2.0) to 90% (MAX_PROGRESS) */
		PRINT_PROGRESS (MIN_PROGRESS + (MAX_PROGRESS - MIN_PROGRESS) / 2.0 + (current_row * columns + current_column) * (((MAX_PROGRESS - MIN_PROGRESS) / gallery) / 2.0));

		g_free (timestamp_text);

		current_column = (current_column + 1) % columns;
		x += output_size + x_padding;
		if (current_column == 0) {
			x = x_padding + output_size;
			y += scale * screenshot_height + y_padding;
			current_row++;
		}
	}

	g_object_unref (layout);

	PROGRESS_DEBUG ("Converting Cairo surface back to pixbuf.");

	/* Create a new pixbuf from the Cairo context */
	pixbuf = cairo_surface_to_pixbuf (cairo_get_target (cr));
	cairo_destroy (cr);

	return pixbuf;
}
Beispiel #29
0
static void
draw_str(struct gra2cairo_local *local, int draw, char *str, struct fontmap *font, int size, int space, int *fw, int *ah, int *dh)
{
  PangoAttribute *attr;
  PangoAttrList *alist;
  PangoLayoutIter *piter;
  int w, h, baseline;

  if (size == 0 || str == NULL) {
    if (fw)
      *fw = 0;

    if (ah)
      *ah = 0;

    if (dh)
      *dh = 0;
    return;
  }

  if (local->layout == NULL) {
    local->layout = pango_cairo_create_layout(local->cairo);
  }

  alist = pango_attr_list_new();
  attr = pango_attr_size_new_absolute(mxd2ph(local, size) * PANGO_SCALE);
  pango_attr_list_insert(alist, attr);

  attr = pango_attr_letter_spacing_new(mxd2ph(local, space) * PANGO_SCALE);
  pango_attr_list_insert(alist, attr);

  pango_layout_set_font_description(local->layout, font->font);
  pango_layout_set_attributes(local->layout, alist);
  pango_attr_list_unref(alist);

  pango_layout_set_text(local->layout, str, -1);

  pango_layout_get_pixel_size(local->layout, &w, &h);
  piter = pango_layout_get_iter(local->layout);
  baseline = pango_layout_iter_get_baseline(piter) / PANGO_SCALE;

  if (fw)
    *fw = w;

  if (ah)
    *ah = baseline;

  if (dh)
    *dh = h - baseline;

  if (draw && str) {
    double x, y;
    double cx, cy;

    x = - local->fontsin * baseline;
    y = - local->fontcos * baseline;

    cairo_get_current_point(local->cairo, &cx, &cy);
    relative_move(local->cairo, x, y);

    cairo_save(local->cairo);
    cairo_rotate(local->cairo, -local->fontdir * G_PI / 180.);
    pango_cairo_update_layout(local->cairo, local->layout);
    if (local->text2path) {
      pango_cairo_layout_path(local->cairo, local->layout);
      cairo_fill(local->cairo);
      cairo_restore(local->cairo);
      cairo_move_to(local->cairo, cx + w * local->fontcos, cy - w * local->fontsin);
    } else {
      pango_cairo_show_layout(local->cairo, local->layout);
      cairo_restore(local->cairo);
      relative_move(local->cairo, w * local->fontcos - x, - w * local->fontsin - y);
    }
  }

  pango_layout_iter_free(piter);
}
Beispiel #30
-1
static gboolean _lib_navigation_draw_callback(GtkWidget *widget, cairo_t *crf, gpointer user_data)
{
  dt_lib_module_t *self = (dt_lib_module_t *)user_data;
  dt_lib_navigation_t *d = (dt_lib_navigation_t *)self->data;

  const int inset = DT_NAVIGATION_INSET;
  GtkAllocation allocation;
  gtk_widget_get_allocation(widget, &allocation);
  int width = allocation.width, height = allocation.height;

  dt_develop_t *dev = darktable.develop;

  /* double buffering of image data: only take new data if valid */
  if(dev->preview_pipe->backbuf && dev->preview_status == DT_DEV_PIXELPIPE_VALID)
  {
    /* re-allocate in case of changed image dimensions */
    if(d->buffer == NULL || dev->preview_pipe->backbuf_width != d->wd || dev->preview_pipe->backbuf_height != d->ht)
    {
      g_free(d->buffer);
      d->wd = dev->preview_pipe->backbuf_width;
      d->ht = dev->preview_pipe->backbuf_height;
      d->buffer = g_malloc0((size_t)d->wd * d->ht * 4 * sizeof(unsigned char));
    }

    /* update buffer if new data is available */
    if(d->buffer && dev->preview_pipe->input_timestamp > d->timestamp)
    {
      dt_pthread_mutex_t *mutex = &dev->preview_pipe->backbuf_mutex;
      dt_pthread_mutex_lock(mutex);
      memcpy(d->buffer, dev->preview_pipe->backbuf, (size_t)d->wd * d->ht * 4 * sizeof(unsigned char));
      d->timestamp = dev->preview_pipe->input_timestamp;
      dt_pthread_mutex_unlock(mutex);
    }
  }

  /* get the current style */
  cairo_surface_t *cst = dt_cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height);
  cairo_t *cr = cairo_create(cst);

  GtkStyleContext *context = gtk_widget_get_style_context(widget);
  gtk_render_background(context, cr, 0, 0, allocation.width, allocation.height);

  width -= 2 * inset;
  height -= 2 * inset;
  cairo_translate(cr, inset, inset);

  /* draw navigation image if available */
  if(d->buffer)
  {
    cairo_save(cr);
    const int wd = d->wd;
    const int ht = d->ht;
    const float scale = fminf(width / (float)wd, height / (float)ht);

    const int stride = cairo_format_stride_for_width(CAIRO_FORMAT_RGB24, wd);
    cairo_surface_t *surface
        = cairo_image_surface_create_for_data(d->buffer, CAIRO_FORMAT_RGB24, wd, ht, stride);
    cairo_translate(cr, width / 2.0, height / 2.0f);
    cairo_scale(cr, scale, scale);
    cairo_translate(cr, -.5f * wd, -.5f * ht);

    // draw shadow around
    float alpha = 1.0f;
    for(int k = 0; k < 4; k++)
    {
      cairo_rectangle(cr, -k / scale, -k / scale, wd + 2 * k / scale, ht + 2 * k / scale);
      cairo_set_source_rgba(cr, 0, 0, 0, alpha);
      alpha *= 0.6f;
      cairo_fill(cr);
    }

    cairo_rectangle(cr, 0, 0, wd - 2, ht - 1);
    cairo_set_source_surface(cr, surface, 0, 0);
    cairo_pattern_set_filter(cairo_get_source(cr), CAIRO_FILTER_FAST);
    cairo_fill(cr);
    cairo_surface_destroy(surface);

    // draw box where we are
    dt_dev_zoom_t zoom = dt_control_get_dev_zoom();
    int closeup = dt_control_get_dev_closeup();
    float zoom_x = dt_control_get_dev_zoom_x();
    float zoom_y = dt_control_get_dev_zoom_y();
    const float min_scale = dt_dev_get_zoom_scale(dev, DT_ZOOM_FIT, closeup ? 2.0 : 1.0, 0);
    const float cur_scale = dt_dev_get_zoom_scale(dev, zoom, closeup ? 2.0 : 1.0, 0);
    // avoid numerical instability for small resolutions:
    double h, w;
    if(cur_scale > min_scale)
    {
      float boxw = 1, boxh = 1;
      dt_dev_check_zoom_bounds(darktable.develop, &zoom_x, &zoom_y, zoom, closeup, &boxw, &boxh);
      cairo_translate(cr, wd * (.5f + zoom_x), ht * (.5f + zoom_y));
      cairo_set_source_rgb(cr, 0., 0., 0.);
      cairo_set_line_width(cr, DT_PIXEL_APPLY_DPI(1.f / scale));
      boxw *= wd;
      boxh *= ht;
      cairo_rectangle(cr, -boxw / 2 - 1, -boxh / 2 - 1, boxw + 2, boxh + 2);
      cairo_stroke(cr);
      cairo_set_source_rgb(cr, 1., 1., 1.);
      cairo_rectangle(cr, -boxw / 2, -boxh / 2, boxw, boxh);
      cairo_stroke(cr);
    }
    cairo_restore(cr);
    if(fabsf(cur_scale - min_scale) > 0.001f)
    {
      /* Zoom % */
      PangoLayout *layout;
      PangoRectangle ink;
      PangoFontDescription *desc = pango_font_description_copy_static(darktable.bauhaus->pango_font_desc);
      pango_font_description_set_weight(desc, PANGO_WEIGHT_BOLD);
      layout = pango_cairo_create_layout(cr);
      const float fontsize = DT_PIXEL_APPLY_DPI(11);
      pango_font_description_set_absolute_size(desc, fontsize * PANGO_SCALE);
      pango_layout_set_font_description(layout, desc);
      cairo_translate(cr, 0, height);
      cairo_set_source_rgba(cr, 1., 1., 1., 0.5);
      cairo_set_line_join(cr, CAIRO_LINE_JOIN_ROUND);

      char zoomline[5];
      snprintf(zoomline, sizeof(zoomline), "%.0f%%", cur_scale * 100);

      pango_layout_set_text(layout, zoomline, -1);
      pango_layout_get_pixel_extents(layout, &ink, NULL);
      h = d->zoom_h = ink.height;
      w = d->zoom_w = ink.width;

      cairo_move_to(cr, width - w - h * 1.1 - ink.x, - fontsize);

      cairo_save(cr);
      cairo_set_line_width(cr, DT_PIXEL_APPLY_DPI(2.0));

      GdkRGBA *color;
      gtk_style_context_get(context, gtk_widget_get_state_flags(widget), "background-color", &color, NULL);

      gdk_cairo_set_source_rgba(cr, color);
      pango_cairo_layout_path(cr, layout);
      cairo_stroke_preserve(cr);
      cairo_set_source_rgb(cr, 0.6, 0.6, 0.6);
      cairo_fill(cr);
      cairo_restore(cr);

      gdk_rgba_free(color);
      pango_font_description_free(desc);
      g_object_unref(layout);

    }
    else
    {
      // draw the zoom-to-fit icon
      cairo_translate(cr, 0, height);
      cairo_set_source_rgb(cr, 0.6, 0.6, 0.6);

      static int height = -1;
      if(height == -1)
      {
        PangoLayout *layout;
        PangoRectangle ink;
        PangoFontDescription *desc = pango_font_description_copy_static(darktable.bauhaus->pango_font_desc);
        pango_font_description_set_weight(desc, PANGO_WEIGHT_BOLD);
        layout = pango_cairo_create_layout(cr);
        pango_font_description_set_absolute_size(desc, DT_PIXEL_APPLY_DPI(11) * PANGO_SCALE);
        pango_layout_set_font_description(layout, desc);
        pango_layout_set_text(layout, "100%", -1); // dummy text, just to get the height
        pango_layout_get_pixel_extents(layout, &ink, NULL);
        height = ink.height;
        pango_font_description_free(desc);
        g_object_unref(layout);
      }

      h = d->zoom_h = height;
      w = h * 1.5;
      float sp = h * 0.6;
      d->zoom_w = w + sp;

      cairo_move_to(cr, width - w - h - sp, -1.0 * h);
      cairo_rectangle(cr, width - w - h - sp, -1.0 * h, w, h);
      cairo_set_source_rgb(cr, 0.2, 0.2, 0.2);
      cairo_fill(cr);

      cairo_set_line_width(cr, DT_PIXEL_APPLY_DPI(2.0));

      cairo_set_source_rgb(cr, 0.6, 0.6, 0.6);
      cairo_move_to(cr, width - w * 0.8 - h - sp, -1.0 * h);
      cairo_line_to(cr, width - w - h - sp, -1.0 * h);
      cairo_line_to(cr, width - w - h - sp, -0.7 * h);
      cairo_stroke(cr);
      cairo_move_to(cr, width - w - h - sp, -0.3 * h);
      cairo_line_to(cr, width - w - h - sp, 0);
      cairo_line_to(cr, width - w * 0.8 - h - sp, 0);
      cairo_stroke(cr);
      cairo_move_to(cr, width - w * 0.2 - h - sp, 0);
      cairo_line_to(cr, width - h - sp, 0);
      cairo_line_to(cr, width - h - sp, -0.3 * h);
      cairo_stroke(cr);
      cairo_move_to(cr, width - h - sp, -0.7 * h);
      cairo_line_to(cr, width - h - sp, -1.0 * h);
      cairo_line_to(cr, width - w * 0.2 - h - sp, -1.0 * h);
      cairo_stroke(cr);
    }

    cairo_move_to(cr, width - 0.95 * h, -0.9 * h);
    cairo_line_to(cr, width - 0.05 * h, -0.9 * h);
    cairo_line_to(cr, width - 0.5 * h, -0.1 * h);
    cairo_fill(cr);
  }

  /* blit memsurface into widget */
  cairo_destroy(cr);
  cairo_set_source_surface(crf, cst, 0, 0);
  cairo_paint(crf);
  cairo_surface_destroy(cst);

  return TRUE;
}