This source file includes following definitions.
- FreeRoundedWindowData
 
- MakeFramePolygonPoints
 
- OnRoundedWindowExpose
 
- OnStyleSet
 
- ActAsRoundedWindow
 
- StopActingAsRoundedWindow
 
- IsActingAsRoundedWindow
 
- SetRoundedWindowEdgesAndBorders
 
- SetRoundedWindowBorderColor
 
#include "chrome/browser/ui/gtk/rounded_window.h"
#include <gtk/gtk.h>
#include <math.h>
#include "base/i18n/rtl.h"
#include "base/logging.h"
#include "chrome/browser/ui/gtk/gtk_util.h"
#include "ui/base/gtk/gtk_signal_registrar.h"
#include "ui/gfx/gtk_compat.h"
namespace gtk_util {
namespace {
const char* kRoundedData = "rounded-window-data";
const int kMinRoundedBorderSize = 8;
struct RoundedWindowData {
  
  int expected_width;
  int expected_height;
  
  GdkColor border_color;
  
  int corner_size;
  
  int rounded_edges;
  
  int drawn_borders;
  
  ui::GtkSignalRegistrar signals;
};
void FreeRoundedWindowData(gpointer data) {
  delete static_cast<RoundedWindowData*>(data);
}
enum FrameType {
  FRAME_MASK,
  FRAME_STROKE,
};
std::vector<GdkPoint> MakeFramePolygonPoints(RoundedWindowData* data,
                                             FrameType type) {
  using gtk_util::MakeBidiGdkPoint;
  int width = data->expected_width;
  int height = data->expected_height;
  int corner_size = data->corner_size;
  std::vector<GdkPoint> points;
  bool ltr = !base::i18n::IsRTL();
  
  
  
  
  int y_off = (type == FRAME_MASK) ? 0 : -1;
  
  int x_off_l = ltr ? y_off : 0;
  
  int x_off_r = !ltr ? -y_off : 0;
  
  
  
  if (type == FRAME_MASK ||
      (data->drawn_borders & (BORDER_LEFT | BORDER_BOTTOM))) {
    if (data->rounded_edges & ROUNDED_BOTTOM_LEFT) {
      if (corner_size >= kMinRoundedBorderSize) {
        
        
        
        for (int x = 0; x <= corner_size; ++x) {
          int y = static_cast<int>(sqrt(static_cast<double>(
              (corner_size * corner_size) - (x * x))));
          if (x > 0) {
            points.push_back(MakeBidiGdkPoint(
                corner_size - x + x_off_r + 1,
                height - (corner_size - y) + y_off, width, ltr));
          }
          points.push_back(MakeBidiGdkPoint(
              corner_size - x + x_off_r,
              height - (corner_size - y) + y_off, width, ltr));
        }
      } else {
        points.push_back(MakeBidiGdkPoint(
            corner_size + x_off_l, height + y_off, width, ltr));
        points.push_back(MakeBidiGdkPoint(
            x_off_r, height - corner_size, width, ltr));
      }
    } else {
      points.push_back(MakeBidiGdkPoint(x_off_r, height + y_off, width, ltr));
    }
  }
  
  if (type == FRAME_MASK ||
      (data->drawn_borders & (BORDER_LEFT | BORDER_TOP))) {
    if (data->rounded_edges & ROUNDED_TOP_LEFT) {
      if (corner_size >= kMinRoundedBorderSize) {
        for (int x = corner_size; x >= 0; --x) {
          int y = static_cast<int>(sqrt(static_cast<double>(
              (corner_size * corner_size) - (x * x))));
          points.push_back(MakeBidiGdkPoint(corner_size - x + x_off_r,
              corner_size - y, width, ltr));
          if (x > 0) {
            points.push_back(MakeBidiGdkPoint(corner_size - x + 1 + x_off_r,
                corner_size - y, width, ltr));
          }
        }
      } else {
        points.push_back(MakeBidiGdkPoint(
            x_off_r, corner_size - 1, width, ltr));
        points.push_back(MakeBidiGdkPoint(
            corner_size + x_off_r - 1, 0, width, ltr));
      }
    } else {
      points.push_back(MakeBidiGdkPoint(x_off_r, 0, width, ltr));
    }
  }
  
  if (type == FRAME_MASK ||
      (data->drawn_borders & (BORDER_TOP | BORDER_RIGHT))) {
    if (data->rounded_edges & ROUNDED_TOP_RIGHT) {
      if (corner_size >= kMinRoundedBorderSize) {
        for (int x = 0; x <= corner_size; ++x) {
          int y = static_cast<int>(sqrt(static_cast<double>(
              (corner_size * corner_size) - (x * x))));
          if (x > 0) {
            points.push_back(MakeBidiGdkPoint(
                width - (corner_size - x) + x_off_l - 1,
                corner_size - y, width, ltr));
          }
          points.push_back(MakeBidiGdkPoint(
              width - (corner_size - x) + x_off_l,
              corner_size - y, width, ltr));
        }
      } else {
        points.push_back(MakeBidiGdkPoint(
            width - corner_size + 1 + x_off_l, 0, width, ltr));
        points.push_back(MakeBidiGdkPoint(
            width + x_off_l, corner_size - 1, width, ltr));
      }
    } else {
      points.push_back(MakeBidiGdkPoint(
          width + x_off_l, 0, width, ltr));
    }
  }
  
  if (type == FRAME_MASK ||
      (data->drawn_borders & (BORDER_RIGHT | BORDER_BOTTOM))) {
    if (data->rounded_edges & ROUNDED_BOTTOM_RIGHT) {
      if (corner_size >= kMinRoundedBorderSize) {
        for (int x = corner_size; x >= 0; --x) {
          int y = static_cast<int>(sqrt(static_cast<double>(
              (corner_size * corner_size) - (x * x))));
          points.push_back(MakeBidiGdkPoint(
              width - (corner_size - x) + x_off_l,
              height - (corner_size - y) + y_off, width, ltr));
          if (x > 0) {
            points.push_back(MakeBidiGdkPoint(
                width - (corner_size - x) + x_off_l - 1,
                height - (corner_size - y) + y_off, width, ltr));
          }
        }
      } else {
        points.push_back(MakeBidiGdkPoint(
            width + x_off_l, height - corner_size, width, ltr));
        points.push_back(MakeBidiGdkPoint(
            width - corner_size + x_off_r, height + y_off, width, ltr));
      }
    } else {
      points.push_back(MakeBidiGdkPoint(
          width + x_off_l, height + y_off, width, ltr));
    }
  }
  return points;
}
gboolean OnRoundedWindowExpose(GtkWidget* widget,
                               GdkEventExpose* event) {
  RoundedWindowData* data = static_cast<RoundedWindowData*>(
      g_object_get_data(G_OBJECT(widget), kRoundedData));
  GtkAllocation allocation;
  gtk_widget_get_allocation(widget, &allocation);
  if (data->expected_width != allocation.width ||
      data->expected_height != allocation.height) {
    data->expected_width = allocation.width;
    data->expected_height = allocation.height;
    
    
    std::vector<GdkPoint> mask_points = MakeFramePolygonPoints(
        data, FRAME_MASK);
    GdkRegion* mask_region = gdk_region_polygon(&mask_points[0],
                                                mask_points.size(),
                                                GDK_EVEN_ODD_RULE);
    gdk_window_shape_combine_region(gtk_widget_get_window(widget),
                                    mask_region, 0, 0);
    gdk_region_destroy(mask_region);
  }
  GdkDrawable* drawable = GDK_DRAWABLE(event->window);
  GdkGC* gc = gdk_gc_new(drawable);
  gdk_gc_set_clip_rectangle(gc, &event->area);
  gdk_gc_set_rgb_fg_color(gc, &data->border_color);
  
  std::vector<GdkPoint> points = MakeFramePolygonPoints(
      data, FRAME_STROKE);
  if (data->drawn_borders == BORDER_ALL) {
    
    
    gdk_draw_polygon(drawable, gc, FALSE, &points[0], points.size());
  } else if (!points.empty()) {
    gdk_draw_lines(drawable, gc, &points[0], points.size());
  }
  g_object_unref(gc);
  return FALSE;  
}
void OnStyleSet(GtkWidget* widget, GtkStyle* previous_style) {
  DCHECK(widget);
  RoundedWindowData* data = static_cast<RoundedWindowData*>(
      g_object_get_data(G_OBJECT(widget), kRoundedData));
  DCHECK(data);
  data->expected_width = -1;
  data->expected_height = -1;
}
}  
void ActAsRoundedWindow(
    GtkWidget* widget, const GdkColor& color, int corner_size,
    int rounded_edges, int drawn_borders) {
  DCHECK(widget);
  DCHECK(!g_object_get_data(G_OBJECT(widget), kRoundedData));
  gtk_widget_set_app_paintable(widget, TRUE);
  RoundedWindowData* data = new RoundedWindowData;
  data->signals.Connect(widget, "expose-event",
                        G_CALLBACK(OnRoundedWindowExpose), NULL);
  data->signals.Connect(widget, "style-set", G_CALLBACK(OnStyleSet), NULL);
  data->expected_width = -1;
  data->expected_height = -1;
  data->border_color = color;
  data->corner_size = corner_size;
  data->rounded_edges = rounded_edges;
  data->drawn_borders = drawn_borders;
  g_object_set_data_full(G_OBJECT(widget), kRoundedData,
                         data, FreeRoundedWindowData);
  if (gtk_widget_get_visible(widget))
    gtk_widget_queue_draw(widget);
}
void StopActingAsRoundedWindow(GtkWidget* widget) {
  g_object_set_data(G_OBJECT(widget), kRoundedData, NULL);
  if (gtk_widget_get_realized(widget))
    gdk_window_shape_combine_mask(gtk_widget_get_window(widget), NULL, 0, 0);
  if (gtk_widget_get_visible(widget))
    gtk_widget_queue_draw(widget);
}
bool IsActingAsRoundedWindow(GtkWidget* widget) {
  return g_object_get_data(G_OBJECT(widget), kRoundedData) != NULL;
}
void SetRoundedWindowEdgesAndBorders(GtkWidget* widget,
                                     int corner_size,
                                     int rounded_edges,
                                     int drawn_borders) {
  DCHECK(widget);
  RoundedWindowData* data = static_cast<RoundedWindowData*>(
      g_object_get_data(G_OBJECT(widget), kRoundedData));
  DCHECK(data);
  data->corner_size = corner_size;
  data->rounded_edges = rounded_edges;
  data->drawn_borders = drawn_borders;
}
void SetRoundedWindowBorderColor(GtkWidget* widget, GdkColor color) {
  DCHECK(widget);
  RoundedWindowData* data = static_cast<RoundedWindowData*>(
      g_object_get_data(G_OBJECT(widget), kRoundedData));
  DCHECK(data);
  data->border_color = color;
}
}