/* * A slider with colored background * * Author: * Lauris Kaplinski * bulia byak * * Copyright (C) 2001-2002 Lauris Kaplinski * * This code is in public domain */ #include #include "sp-color-scales.h" #include "preferences.h" #define SLIDER_WIDTH 96 #define SLIDER_HEIGHT 8 #define ARROW_SIZE 7 enum { GRABBED, DRAGGED, RELEASED, CHANGED, LAST_SIGNAL }; static void sp_color_slider_class_init (SPColorSliderClass *klass); static void sp_color_slider_init (SPColorSlider *slider); static void sp_color_slider_dispose(GObject *object); static void sp_color_slider_realize (GtkWidget *widget); static void sp_color_slider_size_request (GtkWidget *widget, GtkRequisition *requisition); #if GTK_CHECK_VERSION(3,0,0) static void sp_color_slider_get_preferred_width(GtkWidget *widget, gint *minimal_width, gint *natural_width); static void sp_color_slider_get_preferred_height(GtkWidget *widget, gint *minimal_height, gint *natural_height); #else static gboolean sp_color_slider_expose(GtkWidget *widget, GdkEventExpose *event); #endif static void sp_color_slider_size_allocate (GtkWidget *widget, GtkAllocation *allocation); static gboolean sp_color_slider_draw(GtkWidget *widget, cairo_t *cr); static gint sp_color_slider_button_press (GtkWidget *widget, GdkEventButton *event); static gint sp_color_slider_button_release (GtkWidget *widget, GdkEventButton *event); static gint sp_color_slider_motion_notify (GtkWidget *widget, GdkEventMotion *event); static void sp_color_slider_adjustment_changed (GtkAdjustment *adjustment, SPColorSlider *slider); static void sp_color_slider_adjustment_value_changed (GtkAdjustment *adjustment, SPColorSlider *slider); static const guchar *sp_color_slider_render_gradient (gint x0, gint y0, gint width, gint height, gint c[], gint dc[], guint b0, guint b1, guint mask); static const guchar *sp_color_slider_render_map (gint x0, gint y0, gint width, gint height, guchar *map, gint start, gint step, guint b0, guint b1, guint mask); static GtkWidgetClass *parent_class; static guint slider_signals[LAST_SIGNAL] = {0}; GType sp_color_slider_get_type (void) { static GType type = 0; if (!type) { GTypeInfo info = { sizeof (SPColorSliderClass), NULL, NULL, (GClassInitFunc) sp_color_slider_class_init, NULL, NULL, sizeof (SPColorSlider), 0, (GInstanceInitFunc) sp_color_slider_init, NULL }; type = g_type_register_static (GTK_TYPE_WIDGET, "SPColorSlider", &info, (GTypeFlags)0); } return type; } static void sp_color_slider_class_init(SPColorSliderClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS(klass); GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(klass); parent_class = GTK_WIDGET_CLASS(g_type_class_peek_parent(klass)); slider_signals[GRABBED] = g_signal_new ("grabbed", G_TYPE_FROM_CLASS(object_class), (GSignalFlags)(G_SIGNAL_RUN_FIRST | G_SIGNAL_NO_RECURSE), G_STRUCT_OFFSET (SPColorSliderClass, grabbed), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); slider_signals[DRAGGED] = g_signal_new ("dragged", G_TYPE_FROM_CLASS(object_class), (GSignalFlags)(G_SIGNAL_RUN_FIRST | G_SIGNAL_NO_RECURSE), G_STRUCT_OFFSET (SPColorSliderClass, dragged), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); slider_signals[RELEASED] = g_signal_new ("released", G_TYPE_FROM_CLASS(object_class), (GSignalFlags)(G_SIGNAL_RUN_FIRST | G_SIGNAL_NO_RECURSE), G_STRUCT_OFFSET (SPColorSliderClass, released), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); slider_signals[CHANGED] = g_signal_new ("changed", G_TYPE_FROM_CLASS(object_class), (GSignalFlags)(G_SIGNAL_RUN_FIRST | G_SIGNAL_NO_RECURSE), G_STRUCT_OFFSET (SPColorSliderClass, changed), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); object_class->dispose = sp_color_slider_dispose; widget_class->realize = sp_color_slider_realize; #if GTK_CHECK_VERSION(3,0,0) widget_class->get_preferred_width = sp_color_slider_get_preferred_width; widget_class->get_preferred_height = sp_color_slider_get_preferred_height; widget_class->draw = sp_color_slider_draw; #else widget_class->size_request = sp_color_slider_size_request; widget_class->expose_event = sp_color_slider_expose; #endif widget_class->size_allocate = sp_color_slider_size_allocate; /* widget_class->draw_focus = sp_color_slider_draw_focus; */ /* widget_class->draw_default = sp_color_slider_draw_default; */ widget_class->button_press_event = sp_color_slider_button_press; widget_class->button_release_event = sp_color_slider_button_release; widget_class->motion_notify_event = sp_color_slider_motion_notify; } static void sp_color_slider_init (SPColorSlider *slider) { /* We are widget with window */ gtk_widget_set_has_window (GTK_WIDGET(slider), TRUE); slider->dragging = FALSE; slider->adjustment = NULL; slider->value = 0.0; slider->c0[0] = 0x00; slider->c0[1] = 0x00; slider->c0[2] = 0x00; slider->c0[3] = 0xff; slider->cm[0] = 0xff; slider->cm[1] = 0x00; slider->cm[2] = 0x00; slider->cm[3] = 0xff; slider->c1[0] = 0xff; slider->c1[1] = 0xff; slider->c1[2] = 0xff; slider->c1[3] = 0xff; slider->b0 = 0x5f; slider->b1 = 0xa0; slider->bmask = 0x08; slider->map = NULL; } static void sp_color_slider_dispose(GObject *object) { SPColorSlider *slider = SP_COLOR_SLIDER (object); if (slider->adjustment) { g_signal_handlers_disconnect_matched (G_OBJECT (slider->adjustment), G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, slider); g_object_unref (slider->adjustment); slider->adjustment = NULL; } if ((G_OBJECT_CLASS(parent_class))->dispose) (* (G_OBJECT_CLASS(parent_class))->dispose) (object); } static void sp_color_slider_realize (GtkWidget *widget) { GdkWindowAttr attributes; gint attributes_mask; GtkAllocation allocation; gtk_widget_get_allocation(widget, &allocation); gtk_widget_set_realized (widget, TRUE); attributes.window_type = GDK_WINDOW_CHILD; attributes.x = allocation.x; attributes.y = allocation.y; attributes.width = allocation.width; attributes.height = allocation.height; attributes.wclass = GDK_INPUT_OUTPUT; attributes.visual = gdk_screen_get_system_visual(gdk_screen_get_default()); #if !GTK_CHECK_VERSION(3,0,0) attributes.colormap = gdk_screen_get_system_colormap(gdk_screen_get_default()); #endif attributes.event_mask = gtk_widget_get_events (widget); attributes.event_mask |= (GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK); #if GTK_CHECK_VERSION(3,0,0) attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL; #else attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; #endif gtk_widget_set_window(widget, gdk_window_new(gtk_widget_get_parent_window(widget), &attributes, attributes_mask)); gdk_window_set_user_data(gtk_widget_get_window(widget), widget); #if !GTK_CHECK_VERSION(3,0,0) // This doesn't do anything in GTK+ 3 gtk_widget_set_style(widget, gtk_style_attach(gtk_widget_get_style(widget), gtk_widget_get_window(widget))); #endif } static void sp_color_slider_size_request (GtkWidget *widget, GtkRequisition *requisition) { GtkStyle *style = gtk_widget_get_style(widget); requisition->width = SLIDER_WIDTH + style->xthickness * 2; requisition->height = SLIDER_HEIGHT + style->ythickness * 2; } #if GTK_CHECK_VERSION(3,0,0) static void sp_color_slider_get_preferred_width(GtkWidget *widget, gint *minimal_width, gint *natural_width) { GtkRequisition requisition; sp_color_slider_size_request(widget, &requisition); *minimal_width = *natural_width = requisition.width; } static void sp_color_slider_get_preferred_height(GtkWidget *widget, gint *minimal_height, gint *natural_height) { GtkRequisition requisition; sp_color_slider_size_request(widget, &requisition); *minimal_height = *natural_height = requisition.height; } #endif static void sp_color_slider_size_allocate (GtkWidget *widget, GtkAllocation *allocation) { gtk_widget_set_allocation(widget, allocation); if (gtk_widget_get_realized (widget)) { /* Resize GdkWindow */ gdk_window_move_resize(gtk_widget_get_window(widget), allocation->x, allocation->y, allocation->width, allocation->height); } } #if !GTK_CHECK_VERSION(3,0,0) static gboolean sp_color_slider_expose(GtkWidget *widget, GdkEventExpose * /*event*/) { gboolean result = FALSE; if (gtk_widget_is_drawable(widget)) { GdkWindow *window = gtk_widget_get_window(widget); cairo_t *cr = gdk_cairo_create(window); result = sp_color_slider_draw(widget, cr); cairo_destroy(cr); } return result; } #endif static gint sp_color_slider_button_press (GtkWidget *widget, GdkEventButton *event) { SPColorSlider *slider; slider = SP_COLOR_SLIDER (widget); if (event->button == 1) { GtkAllocation allocation; gtk_widget_get_allocation(widget, &allocation); gint cx, cw; cx = gtk_widget_get_style(widget)->xthickness; cw = allocation.width - 2 * cx; g_signal_emit (G_OBJECT (slider), slider_signals[GRABBED], 0); slider->dragging = TRUE; slider->oldvalue = slider->value; ColorScales::setScaled( slider->adjustment, CLAMP ((gfloat) (event->x - cx) / cw, 0.0, 1.0) ); g_signal_emit (G_OBJECT (slider), slider_signals[DRAGGED], 0); #if GTK_CHECK_VERSION(3,0,0) gdk_device_grab(gdk_event_get_device(reinterpret_cast(event)), gtk_widget_get_window(widget), GDK_OWNERSHIP_NONE, FALSE, static_cast(GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK), NULL, event->time); #else gdk_pointer_grab(gtk_widget_get_window(widget), FALSE, static_cast(GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK), NULL, NULL, event->time); #endif } return FALSE; } static gint sp_color_slider_button_release (GtkWidget *widget, GdkEventButton *event) { SPColorSlider *slider; slider = SP_COLOR_SLIDER (widget); if (event->button == 1) { #if GTK_CHECK_VERSION(3,0,0) gdk_device_ungrab(gdk_event_get_device(reinterpret_cast(event)), gdk_event_get_time(reinterpret_cast(event))); #else gdk_pointer_ungrab (event->time); #endif slider->dragging = FALSE; g_signal_emit (G_OBJECT (slider), slider_signals[RELEASED], 0); if (slider->value != slider->oldvalue) g_signal_emit (G_OBJECT (slider), slider_signals[CHANGED], 0); } return FALSE; } static gint sp_color_slider_motion_notify (GtkWidget *widget, GdkEventMotion *event) { SPColorSlider *slider; slider = SP_COLOR_SLIDER (widget); if (slider->dragging) { gint cx, cw; GtkAllocation allocation; gtk_widget_get_allocation(widget, &allocation); cx = gtk_widget_get_style(widget)->xthickness; cw = allocation.width - 2 * cx; ColorScales::setScaled( slider->adjustment, CLAMP ((gfloat) (event->x - cx) / cw, 0.0, 1.0) ); g_signal_emit (G_OBJECT (slider), slider_signals[DRAGGED], 0); } return FALSE; } GtkWidget *sp_color_slider_new(GtkAdjustment *adjustment) { SPColorSlider *slider = SP_COLOR_SLIDER(g_object_new(SP_TYPE_COLOR_SLIDER, NULL)); sp_color_slider_set_adjustment (slider, adjustment); return GTK_WIDGET (slider); } void sp_color_slider_set_adjustment(SPColorSlider *slider, GtkAdjustment *adjustment) { g_return_if_fail (slider != NULL); g_return_if_fail (SP_IS_COLOR_SLIDER (slider)); if (!adjustment) { adjustment = GTK_ADJUSTMENT(gtk_adjustment_new(0.0, 0.0, 1.0, 0.01, 0.0, 0.0)); } else { gtk_adjustment_set_page_increment(adjustment, 0.0); gtk_adjustment_set_page_size(adjustment, 0.0); } if (slider->adjustment != adjustment) { if (slider->adjustment) { g_signal_handlers_disconnect_matched (G_OBJECT (slider->adjustment), G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, slider); g_object_unref (slider->adjustment); } slider->adjustment = adjustment; g_object_ref (adjustment); g_object_ref_sink (adjustment); g_signal_connect (G_OBJECT (adjustment), "changed", G_CALLBACK (sp_color_slider_adjustment_changed), slider); g_signal_connect (G_OBJECT (adjustment), "value_changed", G_CALLBACK (sp_color_slider_adjustment_value_changed), slider); slider->value = ColorScales::getScaled( adjustment ); sp_color_slider_adjustment_changed (adjustment, slider); } } void sp_color_slider_set_colors (SPColorSlider *slider, guint32 start, guint32 mid, guint32 end) { g_return_if_fail (slider != NULL); g_return_if_fail (SP_IS_COLOR_SLIDER (slider)); // Remove any map, if set slider->map = 0; slider->c0[0] = start >> 24; slider->c0[1] = (start >> 16) & 0xff; slider->c0[2] = (start >> 8) & 0xff; slider->c0[3] = start & 0xff; slider->cm[0] = mid >> 24; slider->cm[1] = (mid >> 16) & 0xff; slider->cm[2] = (mid >> 8) & 0xff; slider->cm[3] = mid & 0xff; slider->c1[0] = end >> 24; slider->c1[1] = (end >> 16) & 0xff; slider->c1[2] = (end >> 8) & 0xff; slider->c1[3] = end & 0xff; gtk_widget_queue_draw (GTK_WIDGET (slider)); } void sp_color_slider_set_map (SPColorSlider *slider, const guchar *map) { g_return_if_fail (slider != NULL); g_return_if_fail (SP_IS_COLOR_SLIDER (slider)); slider->map = const_cast(map); gtk_widget_queue_draw (GTK_WIDGET (slider)); } void sp_color_slider_set_background (SPColorSlider *slider, guint dark, guint light, guint size) { g_return_if_fail (slider != NULL); g_return_if_fail (SP_IS_COLOR_SLIDER (slider)); slider->b0 = dark; slider->b1 = light; slider->bmask = size; gtk_widget_queue_draw (GTK_WIDGET (slider)); } static void sp_color_slider_adjustment_changed (GtkAdjustment */*adjustment*/, SPColorSlider *slider) { gtk_widget_queue_draw (GTK_WIDGET (slider)); } static void sp_color_slider_adjustment_value_changed (GtkAdjustment *adjustment, SPColorSlider *slider) { GtkWidget *widget; widget = GTK_WIDGET (slider); if (slider->value != ColorScales::getScaled( adjustment )) { gint cx, cy, cw, ch; GtkStyle *style = gtk_widget_get_style(widget); GtkAllocation allocation; gtk_widget_get_allocation(widget, &allocation); cx = style->xthickness; cy = style->ythickness; cw = allocation.width - 2 * cx; ch = allocation.height - 2 * cy; if ((gint) (ColorScales::getScaled( adjustment ) * cw) != (gint) (slider->value * cw)) { gint ax, ay; gfloat value; value = slider->value; slider->value = ColorScales::getScaled( adjustment ); ax = (int)(cx + value * cw - ARROW_SIZE / 2 - 2); ay = cy; gtk_widget_queue_draw_area (widget, ax, ay, ARROW_SIZE + 4, ch); ax = (int)(cx + slider->value * cw - ARROW_SIZE / 2 - 2); ay = cy; gtk_widget_queue_draw_area (widget, ax, ay, ARROW_SIZE + 4, ch); } else { slider->value = ColorScales::getScaled( adjustment ); } } } static gboolean sp_color_slider_draw(GtkWidget *widget, cairo_t *cr) { SPColorSlider *slider = SP_COLOR_SLIDER(widget); gboolean colorsOnTop = Inkscape::Preferences::get()->getBool("/options/workarounds/colorsontop", false); GtkAllocation allocation; gtk_widget_get_allocation(widget, &allocation); #if GTK_CHECK_VERSION(3,0,0) GtkStyleContext *context = gtk_widget_get_style_context(widget); #else GdkWindow *window = gtk_widget_get_window(widget); GtkStyle *style = gtk_widget_get_style(widget); #endif // Draw shadow if (colorsOnTop) { #if GTK_CHECK_VERSION(3,0,0) gtk_render_frame(context, cr, 0, 0, allocation.width, allocation.height); #else gtk_paint_shadow( style, window, gtk_widget_get_state(widget), GTK_SHADOW_IN, NULL, widget, "colorslider", 0, 0, allocation.width, allocation.height); #endif } /* Paintable part of color gradient area */ GdkRectangle carea; #if GTK_CHECK_VERSION(3,0,0) GtkBorder padding; gtk_style_context_get_padding(context, gtk_widget_get_state_flags(widget), &padding); carea.x = padding.left; carea.y = padding.top; #else carea.x = style->xthickness; carea.y = style->ythickness; #endif carea.width = allocation.width - 2 * carea.x; carea.height = allocation.height - 2 * carea.y; if (slider->map) { /* Render map pixelstore */ gint d = (1024 << 16) / carea.width; gint s = 0; const guchar *b = sp_color_slider_render_map(0, 0, carea.width, carea.height, slider->map, s, d, slider->b0, slider->b1, slider->bmask); if (b != NULL && carea.width > 0) { GdkPixbuf *pb = gdk_pixbuf_new_from_data (b, GDK_COLORSPACE_RGB, 0, 8, carea.width, carea.height, carea.width * 3, NULL, NULL); gdk_cairo_set_source_pixbuf(cr, pb, carea.x, carea.y); cairo_paint(cr); g_object_unref(pb); } } else { gint c[4], dc[4]; /* Render gradient */ // part 1: from c0 to cm if (carea.width > 0) { for (gint i = 0; i < 4; i++) { c[i] = slider->c0[i] << 16; dc[i] = ((slider->cm[i] << 16) - c[i]) / (carea.width/2); } guint wi = carea.width/2; const guchar *b = sp_color_slider_render_gradient(0, 0, wi, carea.height, c, dc, slider->b0, slider->b1, slider->bmask); /* Draw pixelstore 1 */ if (b != NULL && wi > 0) { GdkPixbuf *pb = gdk_pixbuf_new_from_data (b, GDK_COLORSPACE_RGB, 0, 8, wi, carea.height, wi * 3, NULL, NULL); gdk_cairo_set_source_pixbuf(cr, pb, carea.x, carea.y); cairo_paint(cr); g_object_unref(pb); } } // part 2: from cm to c1 if (carea.width > 0) { for (gint i = 0; i < 4; i++) { c[i] = slider->cm[i] << 16; dc[i] = ((slider->c1[i] << 16) - c[i]) / (carea.width/2); } guint wi = carea.width/2; const guchar *b = sp_color_slider_render_gradient(carea.width/2, 0, wi, carea.height, c, dc, slider->b0, slider->b1, slider->bmask); /* Draw pixelstore 2 */ if (b != NULL && wi > 0) { GdkPixbuf *pb = gdk_pixbuf_new_from_data (b, GDK_COLORSPACE_RGB, 0, 8, wi, carea.height, wi * 3, NULL, NULL); gdk_cairo_set_source_pixbuf(cr, pb, carea.width/2 + carea.x, carea.y); cairo_paint(cr); g_object_unref(pb); } } } /* Draw shadow */ if (!colorsOnTop) { #if GTK_CHECK_VERSION(3,0,0) gtk_render_frame(context, cr, 0, 0, allocation.width, allocation.height); #else gtk_paint_shadow( style, window, gtk_widget_get_state(widget), GTK_SHADOW_IN, NULL, widget, "colorslider", 0, 0, allocation.width, allocation.height); #endif } /* Draw arrow */ gint x = (int)(slider->value * (carea.width - 1) - ARROW_SIZE / 2 + carea.x); gint y1 = carea.y; gint y2 = carea.y + carea.height - 1; gint w = ARROW_SIZE; cairo_set_line_width(cr, 1.0); #if GTK_CHECK_VERSION(3,0,0) GdkRGBA white = {1,1,1,1}; GdkRGBA black = {0,0,0,1}; #else GdkColor white, black; gdk_color_parse("#fff", &white); gdk_color_parse("#000", &black); #endif while ( w > 0 ) { #if GTK_CHECK_VERSION(3,0,0) gdk_cairo_set_source_rgba(cr, &white); #else gdk_cairo_set_source_color(cr, &white); #endif cairo_move_to(cr, x - 0.5, y1 + 0.5); cairo_line_to(cr, x + w - 1 + 0.5, y1 + 0.5); cairo_move_to(cr, x - 0.5, y2 + 0.5); cairo_line_to(cr, x + w - 1 + 0.5, y2 + 0.5); cairo_stroke(cr); w -=2; x++; if ( w > 0 ) { #if GTK_CHECK_VERSION(3,0,0) gdk_cairo_set_source_rgba(cr, &black); #else gdk_cairo_set_source_color(cr, &black); #endif cairo_move_to(cr, x - 0.5, y1 + 0.5); cairo_line_to(cr, x + w - 1 + 0.5, y1 + 0.5); cairo_move_to(cr, x - 0.5, y2 + 0.5); cairo_line_to(cr, x + w - 1 + 0.5, y2 + 0.5); cairo_stroke(cr); } y1++; y2--; } return FALSE; } /* Colors are << 16 */ static const guchar * sp_color_slider_render_gradient (gint x0, gint y0, gint width, gint height, gint c[], gint dc[], guint b0, guint b1, guint mask) { static guchar *buf = NULL; static gint bs = 0; guchar *dp; gint x, y; guint r, g, b, a; if (buf && (bs < width * height)) { g_free (buf); buf = NULL; } if (!buf) { buf = g_new (guchar, width * height * 3); bs = width * height; } dp = buf; r = c[0]; g = c[1]; b = c[2]; a = c[3]; for (x = x0; x < x0 + width; x++) { gint cr, cg, cb, ca; guchar *d; cr = r >> 16; cg = g >> 16; cb = b >> 16; ca = a >> 16; d = dp; for (y = y0; y < y0 + height; y++) { guint bg, fc; /* Background value */ bg = ((x & mask) ^ (y & mask)) ? b0 : b1; fc = (cr - bg) * ca; d[0] = bg + ((fc + (fc >> 8) + 0x80) >> 8); fc = (cg - bg) * ca; d[1] = bg + ((fc + (fc >> 8) + 0x80) >> 8); fc = (cb - bg) * ca; d[2] = bg + ((fc + (fc >> 8) + 0x80) >> 8); d += 3 * width; } r += dc[0]; g += dc[1]; b += dc[2]; a += dc[3]; dp += 3; } return buf; } /* Positions are << 16 */ static const guchar * sp_color_slider_render_map (gint x0, gint y0, gint width, gint height, guchar *map, gint start, gint step, guint b0, guint b1, guint mask) { static guchar *buf = NULL; static gint bs = 0; guchar *dp, *sp; gint x, y; if (buf && (bs < width * height)) { g_free (buf); buf = NULL; } if (!buf) { buf = g_new (guchar, width * height * 3); bs = width * height; } dp = buf; for (x = x0; x < x0 + width; x++) { gint cr, cg, cb, ca; guchar *d; sp = map + 4 * (start >> 16); cr = *sp++; cg = *sp++; cb = *sp++; ca = *sp++; d = dp; for (y = y0; y < y0 + height; y++) { guint bg, fc; /* Background value */ bg = ((x & mask) ^ (y & mask)) ? b0 : b1; fc = (cr - bg) * ca; d[0] = bg + ((fc + (fc >> 8) + 0x80) >> 8); fc = (cg - bg) * ca; d[1] = bg + ((fc + (fc >> 8) + 0x80) >> 8); fc = (cb - bg) * ca; d[2] = bg + ((fc + (fc >> 8) + 0x80) >> 8); d += 3 * width; } dp += 3; start += step; } return buf; }