262 lines
10 KiB
C++
262 lines
10 KiB
C++
/*
|
|
* Copyright (C) 2016 Igalia S.L.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
|
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
|
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
|
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
#include "config.h"
|
|
#include "RenderThemeGadget.h"
|
|
|
|
#if !USE(GTK4)
|
|
|
|
#include "FloatRect.h"
|
|
#include "GRefPtrGtk.h"
|
|
|
|
namespace WebCore {
|
|
|
|
std::unique_ptr<RenderThemeGadget> RenderThemeGadget::create(const RenderThemeGadget::Info& info, RenderThemeGadget* parent, const Vector<RenderThemeGadget::Info> siblings, unsigned position)
|
|
{
|
|
switch (info.type) {
|
|
case RenderThemeGadget::Type::Generic:
|
|
return makeUnique<RenderThemeGadget>(info, parent, siblings, position);
|
|
case RenderThemeGadget::Type::Scrollbar:
|
|
return makeUnique<RenderThemeScrollbarGadget>(info, parent, siblings, position);
|
|
}
|
|
|
|
ASSERT_NOT_REACHED();
|
|
return nullptr;
|
|
}
|
|
|
|
static GRefPtr<GtkStyleContext> createStyleContext(GtkWidgetPath* path, GtkStyleContext* parent)
|
|
{
|
|
GRefPtr<GtkStyleContext> context = adoptGRef(gtk_style_context_new());
|
|
gtk_style_context_set_path(context.get(), path);
|
|
gtk_style_context_set_parent(context.get(), parent);
|
|
return context;
|
|
}
|
|
|
|
static void appendElementToPath(GtkWidgetPath* path, const RenderThemeGadget::Info& info)
|
|
{
|
|
// Scrollbars need to use its GType to be able to get non-CSS style properties.
|
|
gtk_widget_path_append_type(path, info.type == RenderThemeGadget::Type::Scrollbar ? GTK_TYPE_SCROLLBAR : G_TYPE_NONE);
|
|
gtk_widget_path_iter_set_object_name(path, -1, info.name);
|
|
for (const auto* className : info.classList)
|
|
gtk_widget_path_iter_add_class(path, -1, className);
|
|
}
|
|
|
|
RenderThemeGadget::RenderThemeGadget(const RenderThemeGadget::Info& info, RenderThemeGadget* parent, const Vector<RenderThemeGadget::Info> siblings, unsigned position)
|
|
{
|
|
GRefPtr<GtkWidgetPath> path = parent ? adoptGRef(gtk_widget_path_copy(gtk_style_context_get_path(parent->context()))) : adoptGRef(gtk_widget_path_new());
|
|
if (!siblings.isEmpty()) {
|
|
GRefPtr<GtkWidgetPath> siblingsPath = adoptGRef(gtk_widget_path_new());
|
|
for (const auto& siblingInfo : siblings)
|
|
appendElementToPath(siblingsPath.get(), siblingInfo);
|
|
gtk_widget_path_append_with_siblings(path.get(), siblingsPath.get(), position);
|
|
} else
|
|
appendElementToPath(path.get(), info);
|
|
m_context = createStyleContext(path.get(), parent ? parent->context() : nullptr);
|
|
}
|
|
|
|
RenderThemeGadget::~RenderThemeGadget() = default;
|
|
|
|
GtkBorder RenderThemeGadget::marginBox() const
|
|
{
|
|
GtkBorder returnValue;
|
|
gtk_style_context_get_margin(m_context.get(), gtk_style_context_get_state(m_context.get()), &returnValue);
|
|
return returnValue;
|
|
}
|
|
|
|
GtkBorder RenderThemeGadget::borderBox() const
|
|
{
|
|
GtkBorder returnValue;
|
|
gtk_style_context_get_border(m_context.get(), gtk_style_context_get_state(m_context.get()), &returnValue);
|
|
return returnValue;
|
|
}
|
|
|
|
GtkBorder RenderThemeGadget::paddingBox() const
|
|
{
|
|
GtkBorder returnValue;
|
|
gtk_style_context_get_padding(m_context.get(), gtk_style_context_get_state(m_context.get()), &returnValue);
|
|
return returnValue;
|
|
}
|
|
|
|
GtkBorder RenderThemeGadget::contentsBox() const
|
|
{
|
|
auto margin = marginBox();
|
|
auto border = borderBox();
|
|
auto padding = paddingBox();
|
|
padding.left += margin.left + border.left;
|
|
padding.right += margin.right + border.right;
|
|
padding.top += margin.top + border.top;
|
|
padding.bottom += margin.bottom + border.bottom;
|
|
return padding;
|
|
}
|
|
|
|
Color RenderThemeGadget::color() const
|
|
{
|
|
GdkRGBA returnValue;
|
|
gtk_style_context_get_color(m_context.get(), gtk_style_context_get_state(m_context.get()), &returnValue);
|
|
return returnValue;
|
|
}
|
|
|
|
Color RenderThemeGadget::backgroundColor() const
|
|
{
|
|
GdkRGBA returnValue;
|
|
|
|
ALLOW_DEPRECATED_DECLARATIONS_BEGIN
|
|
gtk_style_context_get_background_color(m_context.get(), gtk_style_context_get_state(m_context.get()), &returnValue);
|
|
ALLOW_DEPRECATED_DECLARATIONS_END
|
|
|
|
return returnValue;
|
|
}
|
|
|
|
double RenderThemeGadget::opacity() const
|
|
{
|
|
double returnValue;
|
|
gtk_style_context_get(m_context.get(), gtk_style_context_get_state(m_context.get()), "opacity", &returnValue, nullptr);
|
|
return returnValue;
|
|
}
|
|
|
|
GtkStateFlags RenderThemeGadget::state() const
|
|
{
|
|
return gtk_style_context_get_state(m_context.get());
|
|
}
|
|
|
|
void RenderThemeGadget::setState(GtkStateFlags state)
|
|
{
|
|
gtk_style_context_set_state(m_context.get(), state);
|
|
}
|
|
|
|
IntSize RenderThemeGadget::minimumSize() const
|
|
{
|
|
int width, height;
|
|
gtk_style_context_get(m_context.get(), gtk_style_context_get_state(m_context.get()), "min-width", &width, "min-height", &height, nullptr);
|
|
return IntSize(width, height);
|
|
}
|
|
|
|
IntSize RenderThemeGadget::preferredSize() const
|
|
{
|
|
auto margin = marginBox();
|
|
auto border = borderBox();
|
|
auto padding = paddingBox();
|
|
auto minSize = minimumSize();
|
|
minSize.expand(margin.left + margin.right + border.left + border.right + padding.left + padding.right,
|
|
margin.top + margin.bottom + border.top + border.bottom + padding.top + padding.bottom);
|
|
return minSize;
|
|
}
|
|
|
|
bool RenderThemeGadget::render(cairo_t* cr, const FloatRect& paintRect, FloatRect* contentsRect)
|
|
{
|
|
FloatRect rect = paintRect;
|
|
|
|
auto margin = marginBox();
|
|
rect.move(margin.left, margin.top);
|
|
rect.contract(margin.left + margin.right, margin.top + margin.bottom);
|
|
|
|
auto minSize = minimumSize();
|
|
rect.setWidth(std::max<float>(rect.width(), minSize.width()));
|
|
rect.setHeight(std::max<float>(rect.height(), minSize.height()));
|
|
|
|
gtk_render_background(m_context.get(), cr, rect.x(), rect.y(), rect.width(), rect.height());
|
|
gtk_render_frame(m_context.get(), cr, rect.x(), rect.y(), rect.width(), rect.height());
|
|
|
|
if (contentsRect) {
|
|
auto border = borderBox();
|
|
auto padding = paddingBox();
|
|
*contentsRect = rect;
|
|
contentsRect->move(border.left + padding.left, border.top + padding.top);
|
|
contentsRect->contract(border.left + border.right + padding.left + padding.right, border.top + border.bottom + padding.top + padding.bottom);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
RenderThemeBoxGadget::RenderThemeBoxGadget(const RenderThemeGadget::Info& info, GtkOrientation orientation, const Vector<RenderThemeGadget::Info> children, RenderThemeGadget* parent)
|
|
: RenderThemeGadget(info, parent, Vector<RenderThemeGadget::Info>(), 0)
|
|
, m_orientation(orientation)
|
|
{
|
|
m_children.reserveCapacity(children.size());
|
|
unsigned index = 0;
|
|
for (const auto& childInfo : children)
|
|
m_children.uncheckedAppend(RenderThemeGadget::create(childInfo, this, children, index++));
|
|
}
|
|
|
|
IntSize RenderThemeBoxGadget::preferredSize() const
|
|
{
|
|
IntSize childrenSize;
|
|
for (const auto& child : m_children) {
|
|
IntSize childSize = child->preferredSize();
|
|
switch (m_orientation) {
|
|
case GTK_ORIENTATION_HORIZONTAL:
|
|
childrenSize.setWidth(childrenSize.width() + childSize.width());
|
|
childrenSize.setHeight(std::max(childrenSize.height(), childSize.height()));
|
|
break;
|
|
case GTK_ORIENTATION_VERTICAL:
|
|
childrenSize.setWidth(std::max(childrenSize.width(), childSize.width()));
|
|
childrenSize.setHeight(childrenSize.height() + childSize.height());
|
|
break;
|
|
}
|
|
}
|
|
return RenderThemeGadget::preferredSize().expandedTo(childrenSize);
|
|
}
|
|
|
|
RenderThemeScrollbarGadget::RenderThemeScrollbarGadget(const RenderThemeGadget::Info& info, RenderThemeGadget* parent, const Vector<RenderThemeGadget::Info> siblings, unsigned position)
|
|
: RenderThemeGadget(info, parent, siblings, position)
|
|
{
|
|
gboolean hasBackward, hasForward, hasSecondaryBackward, hasSecondaryForward;
|
|
gtk_style_context_get_style(m_context.get(), "has-backward-stepper", &hasBackward, "has-forward-stepper", &hasForward,
|
|
"has-secondary-backward-stepper", &hasSecondaryBackward, "has-secondary-forward-stepper", &hasSecondaryForward, nullptr);
|
|
if (hasBackward)
|
|
m_steppers.add(Steppers::Backward);
|
|
if (hasForward)
|
|
m_steppers.add(Steppers::Forward);
|
|
if (hasSecondaryBackward)
|
|
m_steppers.add(Steppers::SecondaryBackward);
|
|
if (hasSecondaryForward)
|
|
m_steppers.add(Steppers::SecondaryForward);
|
|
}
|
|
|
|
void RenderThemeScrollbarGadget::renderStepper(cairo_t* cr, const FloatRect& paintRect, RenderThemeGadget* stepperGadget, GtkOrientation orientation, Steppers stepper)
|
|
{
|
|
FloatRect contentsRect;
|
|
stepperGadget->render(cr, paintRect, &contentsRect);
|
|
double angle;
|
|
switch (stepper) {
|
|
case Steppers::Backward:
|
|
case Steppers::SecondaryBackward:
|
|
angle = orientation == GTK_ORIENTATION_VERTICAL ? 0 : 3 * (G_PI / 2);
|
|
break;
|
|
case Steppers::Forward:
|
|
case Steppers::SecondaryForward:
|
|
angle = orientation == GTK_ORIENTATION_VERTICAL ? G_PI / 2 : G_PI;
|
|
break;
|
|
}
|
|
|
|
int stepperSize = std::max(contentsRect.width(), contentsRect.height());
|
|
gtk_render_arrow(stepperGadget->context(), cr, angle, contentsRect.x() + (contentsRect.width() - stepperSize) / 2,
|
|
contentsRect.y() + (contentsRect.height() - stepperSize) / 2, stepperSize);
|
|
}
|
|
|
|
} // namespace WebCore
|
|
|
|
#endif // !USE(GTK4)
|