WidgetRenderingContext.cpp [plain text]
#ifdef GTK_API_VERSION_2
#include "config.h"
#include "WidgetRenderingContext.h"
#include "GraphicsContext.h"
#include "GtkVersioning.h"
#include "PlatformContextCairo.h"
#include "RefPtrCairo.h"
#include "RenderThemeGtk.h"
#include "Timer.h"
#include <gdk/gdk.h>
#include <gtk/gtk.h>
#include <wtf/StdLibExtras.h>
namespace WebCore {
static GdkPixmap* gScratchBuffer = 0;
static void purgeScratchBuffer()
{
if (gScratchBuffer)
g_object_unref(gScratchBuffer);
gScratchBuffer = 0;
}
class PurgeScratchBufferTimer : public TimerBase {
private:
virtual void fired() { purgeScratchBuffer(); }
};
static void scheduleScratchBufferPurge()
{
DEFINE_STATIC_LOCAL(PurgeScratchBufferTimer, purgeScratchBufferTimer, ());
if (purgeScratchBufferTimer.isActive())
purgeScratchBufferTimer.stop();
purgeScratchBufferTimer.startOneShot(2);
}
WidgetRenderingContext::WidgetRenderingContext(GraphicsContext* graphicsContext, const IntRect& targetRect)
: m_graphicsContext(graphicsContext)
, m_targetRect(targetRect)
, m_hadError(false)
{
RenderThemeGtk* theme = static_cast<RenderThemeGtk*>(RenderTheme::defaultTheme().get());
if (!theme->m_themePartsHaveRGBAColormap && graphicsContext->gdkWindow()) {
m_target = graphicsContext->gdkWindow();
return;
}
if (graphicsContext->gdkWindow()) {
int maxWidth = 0, maxHeight = 0;
getGdkDrawableSize(graphicsContext->gdkWindow(), &maxWidth, &maxHeight);
m_targetRect.setSize(m_targetRect.size().shrunkTo(IntSize(maxWidth, maxHeight)));
}
static int extraSpace = 15;
m_targetRect.inflate(extraSpace);
m_paintOffset = targetRect.location() - m_targetRect.location();
int width = m_targetRect.width() + (extraSpace * 2);
int height = m_targetRect.height() + (extraSpace * 2);
int scratchWidth = 0;
int scratchHeight = 0;
if (gScratchBuffer)
gdk_pixmap_get_size(gScratchBuffer, &scratchWidth, &scratchHeight);
if (!gScratchBuffer || scratchWidth < width || scratchHeight < height) {
purgeScratchBuffer();
width = (1 + (width >> 5)) << 5;
height = (1 + (height >> 5)) << 5;
gScratchBuffer = gdk_pixmap_new(0, width, height, gdk_colormap_get_visual(theme->m_colormap)->depth);
gdk_drawable_set_colormap(gScratchBuffer, theme->m_colormap);
}
m_target = gScratchBuffer;
RefPtr<cairo_t> scratchBufferContext = adoptRef(gdk_cairo_create(gScratchBuffer));
cairo_set_operator(scratchBufferContext.get(), CAIRO_OPERATOR_CLEAR);
cairo_paint(scratchBufferContext.get());
}
WidgetRenderingContext::~WidgetRenderingContext()
{
RenderThemeGtk* theme = static_cast<RenderThemeGtk*>(RenderTheme::defaultTheme().get());
if (!theme->m_themePartsHaveRGBAColormap && m_graphicsContext->gdkWindow())
return;
if (m_hadError) {
scheduleScratchBufferPurge();
return;
}
cairo_t* cairoContext = m_graphicsContext->platformContext()->cr();
RefPtr<cairo_pattern_t> previousSource(cairo_get_source(cairoContext));
gdk_cairo_set_source_pixmap(cairoContext, gScratchBuffer, m_targetRect.x(), m_targetRect.y());
cairo_rectangle(cairoContext, m_targetRect.x(), m_targetRect.y(), m_targetRect.width(), m_targetRect.height());
cairo_fill(cairoContext);
cairo_set_source(cairoContext, previousSource.get());
scheduleScratchBufferPurge();
}
void WidgetRenderingContext::calculateClipRect(const IntRect& rect, GdkRectangle* clipRect)
{
clipRect->x = m_paintOffset.width() + rect.x();
clipRect->y = m_paintOffset.height() + rect.y();
clipRect->width = m_targetRect.width();
clipRect->height = m_targetRect.height();
}
void WidgetRenderingContext::gtkPaintBox(const IntRect& rect, GtkWidget* widget, GtkStateType stateType, GtkShadowType shadowType, const gchar* detail)
{
GdkRectangle clipRect;
calculateClipRect(rect, &clipRect);
GtkAllocation allocation;
gtk_widget_get_allocation(widget, &allocation);
allocation.x += clipRect.x;
allocation.y += clipRect.y;
gtk_widget_set_allocation(widget, &allocation);
gtk_paint_box(gtk_widget_get_style(widget), m_target, stateType, shadowType, &clipRect,
widget, detail, clipRect.x, clipRect.y, rect.width(), rect.height());
}
void WidgetRenderingContext::gtkPaintFlatBox(const IntRect& rect, GtkWidget* widget, GtkStateType stateType, GtkShadowType shadowType, const gchar* detail)
{
GdkRectangle clipRect;
calculateClipRect(rect, &clipRect);
gtk_paint_flat_box(gtk_widget_get_style(widget), m_target, stateType, shadowType, &clipRect,
widget, detail, clipRect.x, clipRect.y, rect.width(), rect.height());
}
void WidgetRenderingContext::gtkPaintFocus(const IntRect& rect, GtkWidget* widget, GtkStateType stateType, const gchar* detail)
{
GdkRectangle clipRect;
calculateClipRect(rect, &clipRect);
gtk_paint_focus(gtk_widget_get_style(widget), m_target, stateType, &clipRect, widget,
detail, clipRect.x, clipRect.y, rect.width(), rect.height());
}
void WidgetRenderingContext::gtkPaintSlider(const IntRect& rect, GtkWidget* widget, GtkStateType stateType, GtkShadowType shadowType, const gchar* detail, GtkOrientation orientation)
{
GdkRectangle clipRect;
calculateClipRect(rect, &clipRect);
gtk_paint_slider(gtk_widget_get_style(widget), m_target, stateType, shadowType, &clipRect, widget,
detail, clipRect.x, clipRect.y, rect.width(), rect.height(), orientation);
}
void WidgetRenderingContext::gtkPaintCheck(const IntRect& rect, GtkWidget* widget, GtkStateType stateType, GtkShadowType shadowType, const gchar* detail)
{
GdkRectangle clipRect;
calculateClipRect(rect, &clipRect);
gtk_paint_check(gtk_widget_get_style(widget), m_target, stateType, shadowType, &clipRect, widget,
detail, clipRect.x, clipRect.y, rect.width(), rect.height());
}
void WidgetRenderingContext::gtkPaintOption(const IntRect& rect, GtkWidget* widget, GtkStateType stateType, GtkShadowType shadowType, const gchar* detail)
{
GdkRectangle clipRect;
calculateClipRect(rect, &clipRect);
gtk_paint_option(gtk_widget_get_style(widget), m_target, stateType, shadowType, &clipRect, widget,
detail, clipRect.x, clipRect.y, rect.width(), rect.height());
}
void WidgetRenderingContext::gtkPaintShadow(const IntRect& rect, GtkWidget* widget, GtkStateType stateType, GtkShadowType shadowType, const gchar* detail)
{
GdkRectangle clipRect;
calculateClipRect(rect, &clipRect);
gtk_paint_shadow(gtk_widget_get_style(widget), m_target, stateType, shadowType, &clipRect, widget,
detail, clipRect.x, clipRect.y, rect.width(), rect.height());
}
void WidgetRenderingContext::gtkPaintArrow(const IntRect& rect, GtkWidget* widget, GtkStateType stateType, GtkShadowType shadowType, int arrowDirection, const gchar* detail)
{
GdkRectangle clipRect;
calculateClipRect(rect, &clipRect);
gtk_paint_arrow(gtk_widget_get_style(widget), m_target, stateType, shadowType, &clipRect, widget, detail,
static_cast<GtkArrowType>(arrowDirection), TRUE, clipRect.x, clipRect.y, rect.width(), rect.height());
}
void WidgetRenderingContext::gtkPaintVLine(const IntRect& rect, GtkWidget* widget, GtkStateType stateType, const gchar* detail)
{
GdkRectangle clipRect;
calculateClipRect(rect, &clipRect);
gtk_paint_vline(gtk_widget_get_style(widget), m_target, stateType, &clipRect, widget, detail,
clipRect.y, clipRect.y + rect.height(), clipRect.x);
}
}
#endif // GTK_API_VERSION_2