void Border::Render (cairo_t *cr, Region *region, bool path_only) { Brush *background = GetBackground (); Brush *border_brush = GetBorderBrush (); cairo_save (cr); if (!path_only) RenderLayoutClip (cr); CornerRadius r = *GetCornerRadius (); CornerRadius *round = &r; Thickness thickness = *GetBorderThickness (); Rect paint_border = extents; Rect paint_background = paint_border.GrowBy (-thickness); CornerRadius inner_adjusted = *round; inner_adjusted.topLeft = MAX (round->topLeft - MAX (thickness.left, thickness.top) * .5, 0); inner_adjusted.topRight = MAX (round->topRight - MAX (thickness.right, thickness.top) * .5, 0); inner_adjusted.bottomRight = MAX (round->bottomRight - MAX (thickness.right, thickness.bottom) * .5, 0); inner_adjusted.bottomLeft = MAX (round->bottomLeft - MAX (thickness.left, thickness.bottom) * .5, 0); CornerRadius outer_adjusted = *round; outer_adjusted.topLeft = outer_adjusted.topLeft ? MAX (round->topLeft + MAX (thickness.left, thickness.top) * .5, 0) : 0; outer_adjusted.topRight = outer_adjusted.topRight ? MAX (round->topRight + MAX (thickness.right, thickness.top) * .5, 0) : 0; outer_adjusted.bottomRight = outer_adjusted.bottomRight ? MAX (round->bottomRight + MAX (thickness.right, thickness.bottom) * .5, 0) : 0; outer_adjusted.bottomLeft = outer_adjusted.bottomLeft ? MAX (round->bottomLeft + MAX (thickness.left, thickness.bottom) * .5, 0) : 0; /* * NOTE filling this way can leave alpha artifacts between the border fill and bg fill * but some simple inspection of the ms results make me think that is what happens there * too. */ cairo_new_path (cr); cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD); if (border_brush && !paint_border.IsEmpty ()) { border_brush->SetupBrush (cr, paint_border); paint_border.Draw (cr, &outer_adjusted); paint_background.Draw (cr, &inner_adjusted); if (!path_only) border_brush->Fill (cr); } if (background && !paint_background.IsEmpty ()) { background->SetupBrush (cr, paint_background); paint_background.Draw (cr, &inner_adjusted); if (!path_only) background->Fill (cr); } cairo_restore (cr); }
void Grid::PostRender (Context *ctx, Region *region, bool skip_children) { // render our chidren if we need to if (!skip_children) { VisualTreeWalker walker = VisualTreeWalker (this, ZForward, false); while (UIElement *child = walker.Step ()) child->DoRender (ctx, region); } if (GetShowGridLines () && ctx->IsMutable ()) { double offset = 0; double dash = 4; ColumnDefinitionCollection *cols = GetColumnDefinitionsNoAutoCreate (); RowDefinitionCollection *rows = GetRowDefinitionsNoAutoCreate (); cairo_t *cr = ctx->Cairo (); int col_count = cols ? cols->GetCount () : 0; int row_count = rows ? rows->GetCount () : 0; cairo_save (cr); RenderLayoutClip (cr); cairo_set_line_width(cr, 1.0); // Initially render a blue color cairo_set_dash (cr, &dash, 1, offset); cairo_set_source_rgb (cr, 0.4, 0.4, 1.0); cairo_new_path (cr); // Draw gridlines between each pair of columns/rows for (int count = 0; count < 2; count++) { for (int i = 0, offset = 0; i < col_count - 1; i++) { ColumnDefinition *def = cols->GetValueAt (i)->AsColumnDefinition (); offset += def->GetActualWidth (); cairo_move_to (cr, offset, 0); cairo_line_to (cr, offset, GetActualHeight ()); } for (int i = 0, offset = 0; i < row_count - 1; i++) { RowDefinition *def = rows->GetValueAt (i)->AsRowDefinition (); offset += def->GetActualHeight (); cairo_move_to (cr, 0, offset); cairo_line_to (cr, GetActualWidth (), offset); } cairo_stroke (cr); // For the second pass render a yellow color in the gaps between the previous dashes cairo_set_dash (cr, &dash, 1, dash); cairo_set_source_rgb (cr, 1.0, 1.0, 0.3); } cairo_restore (cr); } // Chain up, but skip children since we've already rendered them here. UIElement::PostRender (ctx, region, true); }
void Image::Render (cairo_t *cr, Region *region, bool path_only) { ImageSource *source = GetSource (); cairo_pattern_t *pattern = NULL; cairo_matrix_t matrix; if (!source) return; source->Lock (); cairo_save (cr); Size specified (GetActualWidth (), GetActualHeight ()); Size stretched = ApplySizeConstraints (specified); bool adjust = specified != GetRenderSize (); if (GetStretch () != StretchUniformToFill) specified = specified.Min (stretched); Rect paint = Rect (0, 0, specified.width, specified.height); if (!path_only) { Rect image = Rect (0, 0, source->GetPixelWidth (), source->GetPixelHeight ()); if (GetStretch () == StretchNone) paint = paint.Union (image); if (image.width == 0.0 && image.height == 0.0) goto cleanup; pattern = cairo_pattern_create_for_surface (source->GetSurface (cr)); image_brush_compute_pattern_matrix (&matrix, paint.width, paint.height, image.width, image.height, GetStretch (), AlignmentXCenter, AlignmentYCenter, NULL, NULL); cairo_pattern_set_matrix (pattern, &matrix); #if MAKE_EVERYTHING_SLOW_AND_BUGGY cairo_pattern_set_extend (pattern, CAIRO_EXTEND_PAD); #endif if (cairo_pattern_status (pattern) == CAIRO_STATUS_SUCCESS) { cairo_set_source (cr, pattern); } cairo_pattern_destroy (pattern); } if (adjust) { // FIXME: Propagate error properly MoonError error; specified = MeasureOverrideWithError (specified, &error); paint = Rect ((stretched.width - specified.width) * 0.5, (stretched.height - specified.height) * 0.5, specified.width, specified.height); } if (!path_only) RenderLayoutClip (cr); paint = paint.Intersection (Rect (0, 0, stretched.width, stretched.height)); paint.Draw (cr); if (!path_only) cairo_fill (cr); cleanup: cairo_restore (cr); source->Unlock (); }