text: // Copyright (c) 2009 The Chromium Authors. All rights reserved.
  // Use of this source code is governed by a BSD-style license that can be
  // found in the LICENSE file.
  
  #include "chrome/browser/gtk/sad_tab_gtk.h"
  
  #include <string>
  
  #include "app/gfx/canvas_paint.h"
  #include "app/gfx/font.h"
  #include "app/l10n_util.h"
  #include "app/resource_bundle.h"
  #include "base/gfx/size.h"
  #include "base/lazy_instance.h"
  #include "grit/generated_resources.h"
  #include "grit/theme_resources.h"
  #include "skia/ext/skia_utils.h"
  #include "third_party/skia/include/effects/SkGradientShader.h"
  
  namespace {
  
  // The y offset from the center at which to paint the icon.
  const int kSadTabOffset = -64;
  // The spacing between the icon and the title.
  const int kIconTitleSpacing = 20;
  // The spacing between the title and the message.
  const int kTitleMessageSpacing = 15;
  const SkColor kTitleTextColor = SK_ColorWHITE;
  const SkColor kMessageTextColor = SK_ColorWHITE;
  const SkColor kBackgroundColor = SkColorSetRGB(35, 48, 64);
  const SkColor kBackgroundEndColor = SkColorSetRGB(35, 48, 64);
  
  struct SadTabGtkConstants {
    SadTabGtkConstants()
        : sad_tab_bitmap(
            ResourceBundle::GetSharedInstance().GetBitmapNamed(IDR_SAD_TAB)),
          title_font(
              ResourceBundle::GetSharedInstance().GetFont(
                  ResourceBundle::BaseFont).DeriveFont(2, gfx::Font::BOLD)),
          message_font(
              ResourceBundle::GetSharedInstance().GetFont(
                  ResourceBundle::BaseFont).DeriveFont(1)),
          title(l10n_util::GetString(IDS_SAD_TAB_TITLE)),
          message(l10n_util::GetString(IDS_SAD_TAB_MESSAGE)) {}
  
    const SkBitmap* sad_tab_bitmap;
    gfx::Font title_font;
    gfx::Font message_font;
    std::wstring title;
    std::wstring message;
  };
  
  base::LazyInstance<SadTabGtkConstants>
      g_sad_tab_constants(base::LINKER_INITIALIZED);
  
  }  // namespace
  
  SadTabGtk::SadTabGtk()
    : width_(0),
      height_(0),
      title_y_(0),
      message_y_(0),
      widget_(gtk_drawing_area_new()) {
    gtk_widget_set_double_buffered(widget_.get(), FALSE);
    g_signal_connect(widget_.get(), "expose-event",
                     G_CALLBACK(OnExposeThunk), this);
    g_signal_connect(widget_.get(), "configure-event",
                     G_CALLBACK(OnConfigureThunk), this);
  }
  
  SadTabGtk::~SadTabGtk() {
    widget_.Destroy();
  }
  
  // static
  gboolean SadTabGtk::OnExposeThunk(GtkWidget* widget,
                                    GdkEventExpose* event,
                                    const SadTabGtk* sad_tab) {
    return sad_tab->OnExpose(widget, event);
  }
  
  gboolean SadTabGtk::OnExpose(GtkWidget* widget, GdkEventExpose* event) const {
    gfx::CanvasPaint canvas(event);
    SkPaint paint;
    paint.setShader(skia::CreateGradientShader(0, height_,
                                               kBackgroundColor,
                                               kBackgroundEndColor))->safeUnref();
    paint.setStyle(SkPaint::kFill_Style);
    canvas.drawRectCoords(0, 0,
                          SkIntToScalar(width_),
                          SkIntToScalar(height_),
                          paint);
  
    const SadTabGtkConstants& sad_tab_constants =
        g_sad_tab_constants.Get();
  
    // Paint the sad tab icon.
    canvas.DrawBitmapInt(*sad_tab_constants.sad_tab_bitmap,
                         icon_bounds_.x(),
                         icon_bounds_.y());
  
    // Paint the "Aw, snap!"
    canvas.DrawStringInt(sad_tab_constants.title,
                         sad_tab_constants.title_font,
                         kTitleTextColor,
                         0,
                         title_y_,
                         width_,
                         sad_tab_constants.title_font.height(),
                         gfx::Canvas::TEXT_ALIGN_CENTER);
  
    // Paint the explanatory message.
    canvas.DrawStringInt(
        sad_tab_constants.message,
        sad_tab_constants.message_font,
        kMessageTextColor,
        0,
        message_y_,
        width_,
        99999,  // Let the height be large, and we'll clip if needed.
        gfx::Canvas::TEXT_ALIGN_CENTER |
        gfx::Canvas::MULTI_LINE |
        gfx::Canvas::TEXT_VALIGN_TOP);
  
    return TRUE;
  }
  
  // static
  gboolean SadTabGtk::OnConfigureThunk(GtkWidget* widget,
                                       GdkEventConfigure* event,
                                       SadTabGtk* sad_tab) {
    return sad_tab->OnConfigure(widget, event);
  }
  
  gboolean SadTabGtk::OnConfigure(GtkWidget* widget, GdkEventConfigure* event) {
    const SadTabGtkConstants& sad_tab_constants =
        g_sad_tab_constants.Get();
    width_ = event->width;
    height_= event->height;
    int icon_width = sad_tab_constants.sad_tab_bitmap->width();
    int icon_height = sad_tab_constants.sad_tab_bitmap->height();
    int icon_x = (event->width - icon_width) / 2;
    int icon_y = ((event->height - icon_height) / 2) + kSadTabOffset;
    icon_bounds_.SetRect(icon_x, icon_y, icon_width, icon_height);
  
    title_y_ =
        icon_bounds_.bottom() + kIconTitleSpacing;
    int title_height = sad_tab_constants.title_font.height();
    message_y_ =
        title_y_ + title_height + kTitleMessageSpacing;
    return TRUE;
  }
  