2 * Copyright (C) 2007 Apple Inc.
3 * Copyright (C) 2007 Alp Toker <alp@atoker.com>
4 * Copyright (C) 2008 Collabora Ltd.
5 * Copyright (C) 2008 INdT - Instituto Nokia de Tecnologia
6 * Copyright (C) 2009-2010 ProFUSION embedded systems
7 * Copyright (C) 2009-2011 Samsung Electronics
8 * Copyright (c) 2012 Intel Corporation. All rights reserved.
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Library General Public
12 * License as published by the Free Software Foundation; either
13 * version 2 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Library General Public License for more details.
20 * You should have received a copy of the GNU Library General Public License
21 * along with this library; see the file COPYING.LIB. If not, write to
22 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
23 * Boston, MA 02110-1301, USA.
28 #include "RenderThemeEfl.h"
30 #include "CSSValueKeywords.h"
31 #include "CairoUtilitiesEfl.h"
32 #include "ExceptionCodePlaceholder.h"
33 #include "FloatRoundedRect.h"
34 #include "FontDescription.h"
35 #include "GraphicsContext.h"
36 #include "HTMLInputElement.h"
37 #include "InputTypeNames.h"
38 #include "NotImplemented.h"
40 #include "PaintInfo.h"
41 #include "PlatformContextCairo.h"
42 #include "RenderBox.h"
43 #include "RenderObject.h"
44 #include "RenderProgress.h"
45 #include "RenderSlider.h"
46 #include "ScrollbarThemeEfl.h"
48 #include "UserAgentScripts.h"
49 #include "UserAgentStyleSheets.h"
50 #include <Ecore_Evas.h>
53 #include <wtf/text/CString.h>
54 #include <wtf/text/StringBuilder.h>
55 #include <wtf/text/WTFString.h>
59 // TODO: change from object count to ecore_evas size (bytes)
60 // TODO: as objects are webpage/user defined and they can be very large.
61 #define RENDER_THEME_EFL_PART_CACHE_MAX 32
63 // Initialize default font size.
64 float RenderThemeEfl::defaultFontSize = 16.0f;
66 static const float minCancelButtonSize = 5;
67 static const float maxCancelButtonSize = 21;
69 static const float minSearchDecorationButtonSize = 1;
70 static const float maxSearchDecorationButtonSize = 15;
71 static const float searchFieldDecorationButtonOffset = 3;
73 // Constants for progress tag animation.
74 // These values have been copied from RenderThemeGtk.cpp
75 static const int progressAnimationFrames = 10;
76 static const double progressAnimationInterval = 0.125;
78 static const int sliderThumbWidth = 29;
79 static const int sliderThumbHeight = 11;
81 #define _ASSERT_ON_RELEASE_RETURN(o, fmt, ...) \
82 do { if (!o) { EINA_LOG_CRIT(fmt, ## __VA_ARGS__); ASSERT(o); return; } } while (0)
83 #define _ASSERT_ON_RELEASE_RETURN_VAL(o, val, fmt, ...) \
84 do { if (!o) { EINA_LOG_CRIT(fmt, ## __VA_ARGS__); ASSERT(o); return val; } } while (0)
87 static const char* toEdjeGroup(FormType type)
89 static const char* groups[] = {
90 "webkit/widget/button",
91 "webkit/widget/radio",
92 "webkit/widget/entry",
93 "webkit/widget/checkbox",
94 "webkit/widget/combo",
95 "webkit/widget/progressbar",
96 "webkit/widget/search/field",
97 "webkit/widget/search/results_button",
98 "webkit/widget/search/results_decoration",
99 "webkit/widget/search/cancel_button",
100 "webkit/widget/slider/vertical",
101 "webkit/widget/slider/horizontal",
102 "webkit/widget/slider/thumb_vertical",
103 "webkit/widget/slider/thumb_horizontal",
104 "webkit/widget/spinner",
108 ASSERT((size_t)type < sizeof(groups) / sizeof(groups[0])); // Out of sync?
112 static bool setSourceGroupForEdjeObject(Evas_Object* o, const String& themePath, const char* group)
115 ASSERT(!themePath.isEmpty());
117 if (!edje_object_file_set(o, themePath.utf8().data(), group)) {
118 const char* message = edje_load_error_str(edje_object_load_error_get(o));
119 EINA_LOG_ERR("Could not set theme group '%s' of file '%s': %s", group, themePath.utf8().data(), message);
126 void RenderThemeEfl::adjustSizeConstraints(RenderStyle* style, FormType type) const
130 // These are always valid, even if no theme could be loaded.
131 const ThemePartDesc* desc = m_partDescs + (size_t)type;
133 if (style->minWidth().isIntrinsic())
134 style->setMinWidth(desc->min.width());
135 if (style->minHeight().isIntrinsic())
136 style->setMinHeight(desc->min.height());
138 if (desc->max.width().value() > 0 && style->maxWidth().isIntrinsicOrAuto())
139 style->setMaxWidth(desc->max.width());
140 if (desc->max.height().value() > 0 && style->maxHeight().isIntrinsicOrAuto())
141 style->setMaxHeight(desc->max.height());
143 style->setPaddingTop(desc->padding.top());
144 style->setPaddingBottom(desc->padding.bottom());
145 style->setPaddingLeft(desc->padding.left());
146 style->setPaddingRight(desc->padding.right());
149 static bool isFormElementTooLargeToDisplay(const IntSize& elementSize)
151 // This limit of 20000 pixels is hardcoded inside edje -- anything above this size
152 // will be clipped. This value seems to be reasonable enough so that hardcoding it
153 // here won't be a problem.
154 static const int maxEdjeDimension = 20000;
156 return elementSize.width() > maxEdjeDimension || elementSize.height() > maxEdjeDimension;
159 PassOwnPtr<RenderThemeEfl::ThemePartCacheEntry> RenderThemeEfl::ThemePartCacheEntry::create(const String& themePath, FormType type, const IntSize& size)
161 ASSERT(!themePath.isEmpty());
163 if (isFormElementTooLargeToDisplay(size) || size.isEmpty()) {
164 EINA_LOG_ERR("Cannot render an element of size %dx%d.", size.width(), size.height());
168 OwnPtr<ThemePartCacheEntry> entry = adoptPtr(new ThemePartCacheEntry);
170 entry->m_canvas = EflUniquePtr<Ecore_Evas>(ecore_evas_buffer_new(size.width(), size.height()));
171 if (!entry->canvas()) {
172 EINA_LOG_ERR("ecore_evas_buffer_new(%d, %d) failed.", size.width(), size.height());
176 // By default EFL creates buffers without alpha.
177 ecore_evas_alpha_set(entry->canvas(), EINA_TRUE);
179 entry->m_edje = EflUniquePtr<Evas_Object>(edje_object_add(ecore_evas_get(entry->canvas())));
180 ASSERT(entry->edje());
182 if (!setSourceGroupForEdjeObject(entry->edje(), themePath, toEdjeGroup(type)))
185 entry->m_surface = createSurfaceForBackingStore(entry->canvas());
186 if (!entry->surface())
189 evas_object_resize(entry->edje(), size.width(), size.height());
190 evas_object_show(entry->edje());
195 return entry.release();
198 void RenderThemeEfl::ThemePartCacheEntry::reuse(const String& themePath, FormType newType, const IntSize& newSize)
200 ASSERT(!themePath.isEmpty());
202 if (type != newType) {
204 if (!setSourceGroupForEdjeObject(edje(), themePath, toEdjeGroup(newType))) {
205 type = FormTypeLast; // Invalidate.
210 if (size != newSize) {
212 ecore_evas_resize(canvas(), newSize.width(), newSize.height());
213 evas_object_resize(edje(), newSize.width(), newSize.height());
215 m_surface = createSurfaceForBackingStore(canvas());
217 type = FormTypeLast; // Invalidate;
223 RenderThemeEfl::ThemePartCacheEntry* RenderThemeEfl::getThemePartFromCache(FormType type, const IntSize& size)
227 Eina_List* reusableNode = 0;
229 // Look for the item in the cache.
230 EINA_LIST_FOREACH(m_partCache, node, data) {
231 ThemePartCacheEntry* cachedEntry = static_cast<ThemePartCacheEntry*>(data);
232 if (cachedEntry->size == size) {
233 if (cachedEntry->type == type) {
234 // Found the right item, move it to the head of the list
236 m_partCache = eina_list_promote_list(m_partCache, node);
239 // We reuse in priority the last item in the list that has
240 // the requested size.
245 if (eina_list_count(m_partCache) < RENDER_THEME_EFL_PART_CACHE_MAX) {
246 ThemePartCacheEntry* entry = ThemePartCacheEntry::create(themePath(), type, size).leakPtr();
248 m_partCache = eina_list_prepend(m_partCache, entry);
253 // The cache is full, reuse the last item we found that had the
254 // requested size to avoid resizing. If there was none, reuse
255 // the last item of the list.
257 reusableNode = eina_list_last(m_partCache);
259 ThemePartCacheEntry* reusedEntry = static_cast<ThemePartCacheEntry*>(eina_list_data_get(reusableNode));
261 reusedEntry->reuse(themePath(), type, size);
262 m_partCache = eina_list_promote_list(m_partCache, reusableNode);
267 void RenderThemeEfl::clearThemePartCache()
270 EINA_LIST_FREE(m_partCache, data)
271 delete static_cast<ThemePartCacheEntry*>(data);
275 void RenderThemeEfl::applyEdjeStateFromForm(Evas_Object* object, const ControlStates* states, bool haveBackground)
277 const char *signals[] = { // keep in sync with WebCore/platform/ThemeTypes.h
290 edje_object_signal_emit(object, "reset", "");
292 for (size_t i = 0; i < WTF_ARRAY_LENGTH(signals); ++i) {
293 if (states->states() & (1 << i))
294 edje_object_signal_emit(object, signals[i], "");
298 edje_object_signal_emit(object, "styled", "");
301 void RenderThemeEfl::applyEdjeRTLState(Evas_Object* edje, const RenderObject& object, FormType type, const IntRect& rect)
303 if (type == SliderVertical || type == SliderHorizontal) {
304 if (!object.isSlider())
305 return; // probably have -webkit-appearance: slider..
307 const RenderSlider* renderSlider = toRenderSlider(&object);
308 HTMLInputElement& input = renderSlider->element();
309 double valueRange = input.maximum() - input.minimum();
311 OwnPtr<Edje_Message_Float_Set> msg = adoptPtr(static_cast<Edje_Message_Float_Set*>(::operator new (sizeof(Edje_Message_Float_Set) + sizeof(double))));
314 // The first parameter of the message decides if the progress bar
315 // grows from the end of the slider or from the beginning. On vertical
316 // sliders, it should always be the same and will not be affected by
317 // text direction settings.
318 if (object.style().direction() == RTL || type == SliderVertical)
323 msg->val[1] = (input.valueAsNumber() - input.minimum()) / valueRange;
324 edje_object_message_send(edje, EDJE_MESSAGE_FLOAT_SET, 0, msg.get());
325 } else if (type == ProgressBar) {
326 const RenderProgress* renderProgress = toRenderProgress(&object);
328 int max = rect.width();
329 double value = renderProgress->position();
331 OwnPtr<Edje_Message_Float_Set> msg = adoptPtr(static_cast<Edje_Message_Float_Set*>(::operator new (sizeof(Edje_Message_Float_Set) + sizeof(double))));
334 if (object.style().direction() == RTL)
335 msg->val[0] = (1.0 - value) * max;
339 edje_object_message_send(edje, EDJE_MESSAGE_FLOAT_SET, 0, msg.get());
343 bool RenderThemeEfl::isControlStyled(const RenderStyle* style, const BorderData& border, const FillLayer& background, const Color& backgroundColor) const
345 return RenderTheme::isControlStyled(style, border, background, backgroundColor) || style->appearance() == MenulistButtonPart;
348 bool RenderThemeEfl::paintThemePart(const RenderObject& object, FormType type, const PaintInfo& info, const IntRect& rect)
351 _ASSERT_ON_RELEASE_RETURN_VAL(edje(), false, "Could not paint native HTML part due to missing theme.");
353 ThemePartCacheEntry* entry = getThemePartFromCache(type, rect.size());
357 bool haveBackgroundColor = isControlStyled(&object.style(), object.style().border(), *object.style().backgroundLayers(), Color::white);
358 ControlStates states(extractControlStatesForRenderer(object));
359 applyEdjeStateFromForm(entry->edje(), &states, haveBackgroundColor);
361 applyEdjeRTLState(entry->edje(), object, type, rect);
363 edje_object_calc_force(entry->edje());
364 edje_object_message_signal_process(entry->edje());
365 evas_render(ecore_evas_get(entry->canvas()));
367 cairo_t* cairo = info.context->platformContext()->cr();
371 cairo_set_source_surface(cairo, entry->surface(), rect.x(), rect.y());
372 cairo_paint_with_alpha(cairo, 1.0);
373 cairo_restore(cairo);
378 PassRefPtr<RenderTheme> RenderThemeEfl::create(Page* page)
380 return adoptRef(new RenderThemeEfl(page));
383 PassRefPtr<RenderTheme> RenderTheme::themeForPage(Page* page)
386 return RenderThemeEfl::create(page);
388 static RenderTheme* fallback = RenderThemeEfl::create(0).leakRef();
392 static void applyColorCallback(void* data, Evas_Object*, const char* /* signal */, const char* colorClass)
394 RenderThemeEfl* that = static_cast<RenderThemeEfl*>(data);
395 that->setColorFromThemeClass(colorClass);
396 that->platformColorsDidChange(); // Triggers relayout.
399 static bool fillColorsFromEdjeClass(Evas_Object* o, const char* colorClass, Color* color1, Color* color2 = 0, Color* color3 = 0)
405 if (!edje_object_color_class_get(o, colorClass, &r1, &g1, &b1, &a1, &r2, &g2, &b2, &a2, &r3, &g3, &b3, &a3))
409 color1->setRGB(makeRGBA(r1, g1, b1, a1));
411 color2->setRGB(makeRGBA(r2, g2, b2, a2));
413 color3->setRGB(makeRGBA(r3, g3, b3, a3));
418 void RenderThemeEfl::setColorFromThemeClass(const char* colorClass)
422 if (!strcmp("webkit/selection/foreground", colorClass))
423 m_supportsSelectionForegroundColor = fillColorsFromEdjeClass(edje(), colorClass, &m_activeSelectionForegroundColor, &m_inactiveSelectionForegroundColor);
424 else if (!strcmp("webkit/selection/background", colorClass))
425 fillColorsFromEdjeClass(edje(), colorClass, &m_activeSelectionBackgroundColor, &m_inactiveSelectionBackgroundColor);
426 else if (!strcmp("webkit/focus_ring", colorClass)) {
427 if (!fillColorsFromEdjeClass(edje(), colorClass, &m_focusRingColor))
430 // platformFocusRingColor() is only used for the default theme (without page)
431 // The following is ugly, but no other way to do it unless we change it to use page themes as much as possible.
432 RenderTheme::setCustomFocusRingColor(m_focusRingColor);
436 void RenderThemeEfl::setThemePath(const String& newThemePath)
438 if (newThemePath == m_themePath)
441 if (newThemePath.isEmpty()) {
442 EINA_LOG_CRIT("No valid theme defined, things will not work properly.");
446 String oldThemePath = m_themePath;
447 m_themePath = newThemePath;
449 // Keep the consistence by restoring the previous theme path
450 // if we cannot load the new one.
452 m_themePath = oldThemePath;
455 String RenderThemeEfl::themePath() const
460 edje_object_file_get(edje(), &path, 0);
461 ASSERT(m_themePath == path);
467 bool RenderThemeEfl::loadTheme()
469 ASSERT(!m_themePath.isEmpty());
472 m_canvas = EflUniquePtr<Ecore_Evas>(ecore_evas_buffer_new(1, 1));
473 _ASSERT_ON_RELEASE_RETURN_VAL(canvas(), false,
474 "Could not create canvas required by theme, things will not work properly.");
477 EflUniquePtr<Evas_Object> o = EflUniquePtr<Evas_Object>(edje_object_add(ecore_evas_get(canvas())));
478 _ASSERT_ON_RELEASE_RETURN_VAL(o, false, "Could not create new base Edje object.");
480 if (!setSourceGroupForEdjeObject(o.get(), m_themePath, "webkit/base"))
481 return false; // Keep current theme.
483 // Invalidate existing theme part cache.
485 clearThemePartCache();
487 // Set new loaded theme, and apply it.
488 m_edje = std::move(o);
490 const char* thickness = edje_object_data_get(m_edje.get(), "scrollbar.thickness");
491 if (thickness && !Settings::mockScrollbarsEnabled())
492 static_cast<ScrollbarThemeEfl*>(ScrollbarTheme::theme())->setScrollbarThickness(atoi(thickness));
494 edje_object_signal_callback_add(edje(), "color_class,set", "webkit/selection/foreground", applyColorCallback, this);
495 edje_object_signal_callback_add(edje(), "color_class,set", "webkit/selection/background", applyColorCallback, this);
496 edje_object_signal_callback_add(edje(), "color_class,set", "webkit/focus_ring", applyColorCallback, this);
498 applyPartDescriptionsFrom(m_themePath);
500 setColorFromThemeClass("webkit/selection/foreground");
501 setColorFromThemeClass("webkit/selection/background");
502 setColorFromThemeClass("webkit/focus_ring");
504 platformColorsDidChange(); // Schedules a relayout, do last.
509 void RenderThemeEfl::applyPartDescriptionFallback(ThemePartDesc* desc)
511 desc->min.setWidth(Length(0, Fixed));
512 desc->min.setHeight(Length(0, Fixed));
514 desc->max.setWidth(Length(0, Fixed));
515 desc->max.setHeight(Length(0, Fixed));
517 desc->padding = LengthBox(0, 0, 0, 0);
520 void RenderThemeEfl::applyPartDescription(Evas_Object* object, ThemePartDesc* desc)
522 Evas_Coord minw, minh, maxw, maxh;
524 edje_object_size_min_get(object, &minw, &minh);
526 edje_object_size_min_calc(object, &minw, &minh);
528 desc->min.setWidth(Length(minw, Fixed));
529 desc->min.setHeight(Length(minh, Fixed));
531 edje_object_size_max_get(object, &maxw, &maxh);
532 desc->max.setWidth(Length(maxw, Fixed));
533 desc->max.setHeight(Length(maxh, Fixed));
535 if (!edje_object_part_exists(object, "text_confinement"))
536 desc->padding = LengthBox(0, 0, 0, 0);
538 Evas_Coord px, py, pw, ph;
539 Evas_Coord ox = 0, oy = 0, ow = 0, oh = 0;
550 if (maxw > 0 && ow > maxw)
552 if (maxh > 0 && oh > maxh)
555 evas_object_move(object, ox, oy);
556 evas_object_resize(object, ow, oh);
557 edje_object_calc_force(object);
558 edje_object_message_signal_process(object);
559 edje_object_part_geometry_get(object, "text_confinement", &px, &py, &pw, &ph);
562 b = (oh + oy) - (ph + py);
565 r = (ow + ox) - (pw + px);
567 desc->padding = LengthBox(t, r, b, l);
571 void RenderThemeEfl::applyPartDescriptionsFrom(const String& themePath)
573 EflUniquePtr<Evas_Object> temp = EflUniquePtr<Evas_Object>(edje_object_add(ecore_evas_get(canvas())));
574 _ASSERT_ON_RELEASE_RETURN(temp, "Could not create Edje object.");
576 for (size_t i = 0; i < FormTypeLast; i++) {
577 FormType type = static_cast<FormType>(i);
578 m_partDescs[i].type = type;
579 if (!setSourceGroupForEdjeObject(temp.get(), themePath, toEdjeGroup(type)))
580 applyPartDescriptionFallback(m_partDescs + i);
582 applyPartDescription(temp.get(), m_partDescs + i);
586 RenderThemeEfl::RenderThemeEfl(Page* page)
589 , m_activeSelectionBackgroundColor(0, 0, 255)
590 , m_activeSelectionForegroundColor(Color::white)
591 , m_inactiveSelectionBackgroundColor(0, 0, 128)
592 , m_inactiveSelectionForegroundColor(200, 200, 200)
593 , m_focusRingColor(32, 32, 224, 224)
594 , m_sliderThumbColor(Color::darkGray)
595 , m_supportsSelectionForegroundColor(false)
600 RenderThemeEfl::~RenderThemeEfl()
602 clearThemePartCache();
605 static bool supportsFocus(ControlPart appearance)
607 switch (appearance) {
612 case SearchFieldPart:
616 case SliderVerticalPart:
617 case SliderHorizontalPart:
624 bool RenderThemeEfl::supportsFocusRing(const RenderStyle* style) const
626 return supportsFocus(style->appearance());
629 bool RenderThemeEfl::controlSupportsTints(const RenderObject& object) const
631 return isEnabled(object);
634 int RenderThemeEfl::baselinePosition(const RenderObject& object) const
639 if (object.style().appearance() == CheckboxPart
640 || object.style().appearance() == RadioPart)
641 return toRenderBox(&object)->marginTop() + toRenderBox(&object)->height() - 3;
643 return RenderTheme::baselinePosition(object);
646 Color RenderThemeEfl::platformActiveSelectionBackgroundColor() const
649 return m_activeSelectionBackgroundColor;
652 Color RenderThemeEfl::platformInactiveSelectionBackgroundColor() const
655 return m_inactiveSelectionBackgroundColor;
658 Color RenderThemeEfl::platformActiveSelectionForegroundColor() const
661 return m_activeSelectionForegroundColor;
664 Color RenderThemeEfl::platformInactiveSelectionForegroundColor() const
667 return m_inactiveSelectionForegroundColor;
670 Color RenderThemeEfl::platformFocusRingColor() const
673 return m_focusRingColor;
676 bool RenderThemeEfl::supportsSelectionForegroundColors() const
679 return m_supportsSelectionForegroundColor;
682 bool RenderThemeEfl::paintSliderTrack(const RenderObject& object, const PaintInfo& info, const IntRect& rect)
684 if (object.style().appearance() == SliderHorizontalPart)
685 paintThemePart(object, SliderHorizontal, info, rect);
687 paintThemePart(object, SliderVertical, info, rect);
689 #if ENABLE(DATALIST_ELEMENT)
690 paintSliderTicks(object, info, rect);
696 void RenderThemeEfl::adjustSliderTrackStyle(StyleResolver*, RenderStyle* style, Element*) const
698 style->setBoxShadow(nullptr);
701 void RenderThemeEfl::adjustSliderThumbStyle(StyleResolver* styleResolver, RenderStyle* style, Element* element) const
703 RenderTheme::adjustSliderThumbStyle(styleResolver, style, element);
704 style->setBoxShadow(nullptr);
707 void RenderThemeEfl::adjustSliderThumbSize(RenderStyle* style, Element*) const
709 ControlPart part = style->appearance();
710 if (part == SliderThumbVerticalPart) {
711 style->setWidth(Length(sliderThumbHeight, Fixed));
712 style->setHeight(Length(sliderThumbWidth, Fixed));
713 } else if (part == SliderThumbHorizontalPart) {
714 style->setWidth(Length(sliderThumbWidth, Fixed));
715 style->setHeight(Length(sliderThumbHeight, Fixed));
719 #if ENABLE(DATALIST_ELEMENT)
720 IntSize RenderThemeEfl::sliderTickSize() const
722 return IntSize(1, 6);
725 int RenderThemeEfl::sliderTickOffsetFromTrackCenter() const
727 static const int sliderTickOffset = -12;
729 return sliderTickOffset;
732 LayoutUnit RenderThemeEfl::sliderTickSnappingThreshold() const
734 // The same threshold value as the Chromium port.
739 bool RenderThemeEfl::supportsDataListUI(const AtomicString& type) const
741 #if ENABLE(DATALIST_ELEMENT)
742 // FIXME: We need to support other types.
743 return type == InputTypeNames::email()
744 || type == InputTypeNames::range()
745 || type == InputTypeNames::search()
746 || type == InputTypeNames::url();
753 bool RenderThemeEfl::paintSliderThumb(const RenderObject& object, const PaintInfo& info, const IntRect& rect)
755 if (object.style().appearance() == SliderThumbHorizontalPart)
756 paintThemePart(object, SliderThumbHorizontal, info, rect);
758 paintThemePart(object, SliderThumbVertical, info, rect);
763 void RenderThemeEfl::adjustCheckboxStyle(StyleResolver* styleResolver, RenderStyle* style, Element* element) const
765 if (!m_page && element && element->document().page()) {
766 static_cast<RenderThemeEfl&>(element->document().page()->theme()).adjustCheckboxStyle(styleResolver, style, element);
770 adjustSizeConstraints(style, CheckBox);
772 style->resetBorder();
774 const ThemePartDesc* desc = m_partDescs + (size_t)CheckBox;
775 if (style->width().value() < desc->min.width().value())
776 style->setWidth(desc->min.width());
777 if (style->height().value() < desc->min.height().value())
778 style->setHeight(desc->min.height());
781 bool RenderThemeEfl::paintCheckbox(const RenderObject& object, const PaintInfo& info, const IntRect& rect)
783 return paintThemePart(object, CheckBox, info, rect);
786 void RenderThemeEfl::adjustRadioStyle(StyleResolver* styleResolver, RenderStyle* style, Element* element) const
788 if (!m_page && element && element->document().page()) {
789 static_cast<RenderThemeEfl&>(element->document().page()->theme()).adjustRadioStyle(styleResolver, style, element);
793 adjustSizeConstraints(style, RadioButton);
795 style->resetBorder();
797 const ThemePartDesc* desc = m_partDescs + (size_t)RadioButton;
798 if (style->width().value() < desc->min.width().value())
799 style->setWidth(desc->min.width());
800 if (style->height().value() < desc->min.height().value())
801 style->setHeight(desc->min.height());
804 bool RenderThemeEfl::paintRadio(const RenderObject& object, const PaintInfo& info, const IntRect& rect)
806 return paintThemePart(object, RadioButton, info, rect);
809 void RenderThemeEfl::adjustButtonStyle(StyleResolver* styleResolver, RenderStyle* style, Element* element) const
811 if (!m_page && element && element->document().page()) {
812 static_cast<RenderThemeEfl&>(element->document().page()->theme()).adjustButtonStyle(styleResolver, style, element);
816 // adjustSizeConstrains can make SquareButtonPart's size wrong (by adjusting paddings), so call it only for PushButtonPart and ButtonPart
817 if (style->appearance() == PushButtonPart || style->appearance() == ButtonPart)
818 adjustSizeConstraints(style, Button);
821 bool RenderThemeEfl::paintButton(const RenderObject& object, const PaintInfo& info, const IntRect& rect)
823 return paintThemePart(object, Button, info, rect);
826 void RenderThemeEfl::adjustMenuListStyle(StyleResolver* styleResolver, RenderStyle* style, Element* element) const
828 if (!m_page && element && element->document().page()) {
829 static_cast<RenderThemeEfl&>(element->document().page()->theme()).adjustMenuListStyle(styleResolver, style, element);
832 adjustSizeConstraints(style, ComboBox);
833 style->resetBorder();
834 style->setWhiteSpace(PRE);
836 style->setLineHeight(RenderStyle::initialLineHeight());
839 bool RenderThemeEfl::paintMenuList(const RenderObject& object, const PaintInfo& info, const FloatRect& rect)
841 return paintThemePart(object, ComboBox, info, IntRect(rect));
844 void RenderThemeEfl::adjustMenuListButtonStyle(StyleResolver& styleResolver, RenderStyle& style, Element& element) const
846 // Height is locked to auto if height is not specified.
847 style.setHeight(Length(Auto));
849 // The <select> box must be at least 12px high for the button to render the text inside the box without clipping.
850 const int dropDownBoxMinHeight = 12;
852 // Calculate min-height of the <select> element.
853 int minHeight = style.fontMetrics().height();
854 minHeight = std::max(minHeight, dropDownBoxMinHeight);
855 style.setMinHeight(Length(minHeight, Fixed));
857 adjustMenuListStyle(&styleResolver, &style, &element);
860 bool RenderThemeEfl::paintMenuListButtonDecorations(const RenderObject& object, const PaintInfo& info, const FloatRect& rect)
862 return paintMenuList(object, info, rect);
865 void RenderThemeEfl::adjustTextFieldStyle(StyleResolver* styleResolver, RenderStyle* style, Element* element) const
867 if (!m_page && element && element->document().page()) {
868 static_cast<RenderThemeEfl&>(element->document().page()->theme()).adjustTextFieldStyle(styleResolver, style, element);
871 adjustSizeConstraints(style, TextField);
872 style->resetBorder();
875 bool RenderThemeEfl::paintTextField(const RenderObject& object, const PaintInfo& info, const FloatRect& rect)
877 return paintThemePart(object, TextField, info, IntRect(rect));
880 void RenderThemeEfl::adjustTextAreaStyle(StyleResolver*, RenderStyle*, Element*) const
884 bool RenderThemeEfl::paintTextArea(const RenderObject& object, const PaintInfo& info, const FloatRect& rect)
886 return paintTextField(object, info, rect);
889 void RenderThemeEfl::adjustSearchFieldResultsButtonStyle(StyleResolver* styleResolver, RenderStyle* style, Element* element) const
891 if (!m_page && element && element->document().page()) {
892 static_cast<RenderThemeEfl&>(element->document().page()->theme()).adjustSearchFieldResultsButtonStyle(styleResolver, style, element);
895 adjustSizeConstraints(style, SearchFieldResultsButton);
896 style->resetBorder();
897 style->setWhiteSpace(PRE);
899 float fontScale = style->fontSize() / defaultFontSize;
900 int decorationSize = lroundf(std::min(std::max(minSearchDecorationButtonSize, defaultFontSize * fontScale), maxSearchDecorationButtonSize));
902 style->setWidth(Length(decorationSize + searchFieldDecorationButtonOffset, Fixed));
903 style->setHeight(Length(decorationSize, Fixed));
906 bool RenderThemeEfl::paintSearchFieldResultsButton(const RenderObject& object, const PaintInfo& info, const IntRect& rect)
908 return paintThemePart(object, SearchFieldResultsButton, info, rect);
911 void RenderThemeEfl::adjustSearchFieldResultsDecorationPartStyle(StyleResolver* styleResolver, RenderStyle* style, Element* element) const
913 if (!m_page && element && element->document().page()) {
914 static_cast<RenderThemeEfl&>(element->document().page()->theme()).adjustSearchFieldResultsDecorationPartStyle(styleResolver, style, element);
917 adjustSizeConstraints(style, SearchFieldResultsDecoration);
918 style->resetBorder();
919 style->setWhiteSpace(PRE);
921 float fontScale = style->fontSize() / defaultFontSize;
922 int decorationSize = lroundf(std::min(std::max(minSearchDecorationButtonSize, defaultFontSize * fontScale), maxSearchDecorationButtonSize));
924 style->setWidth(Length(decorationSize + searchFieldDecorationButtonOffset, Fixed));
925 style->setHeight(Length(decorationSize, Fixed));
928 bool RenderThemeEfl::paintSearchFieldResultsDecorationPart(const RenderObject& object, const PaintInfo& info, const IntRect& rect)
930 return paintThemePart(object, SearchFieldResultsDecoration, info, rect);
933 void RenderThemeEfl::adjustSearchFieldCancelButtonStyle(StyleResolver* styleResolver, RenderStyle* style, Element* element) const
935 if (!m_page && element && element->document().page()) {
936 static_cast<RenderThemeEfl&>(element->document().page()->theme()).adjustSearchFieldCancelButtonStyle(styleResolver, style, element);
939 adjustSizeConstraints(style, SearchFieldCancelButton);
940 style->resetBorder();
941 style->setWhiteSpace(PRE);
943 // Logic taken from RenderThemeChromium.cpp.
944 // Scale the button size based on the font size.
945 float fontScale = style->fontSize() / defaultFontSize;
946 int cancelButtonSize = lroundf(std::min(std::max(minCancelButtonSize, defaultFontSize * fontScale), maxCancelButtonSize));
948 style->setWidth(Length(cancelButtonSize, Fixed));
949 style->setHeight(Length(cancelButtonSize, Fixed));
952 bool RenderThemeEfl::paintSearchFieldCancelButton(const RenderObject& object, const PaintInfo& info, const IntRect& rect)
954 return paintThemePart(object, SearchFieldCancelButton, info, rect);
957 void RenderThemeEfl::adjustSearchFieldStyle(StyleResolver* styleResolver, RenderStyle* style, Element* element) const
959 if (!m_page && element && element->document().page()) {
960 static_cast<RenderThemeEfl&>(element->document().page()->theme()).adjustSearchFieldStyle(styleResolver, style, element);
963 adjustSizeConstraints(style, SearchField);
964 style->resetBorder();
965 style->setWhiteSpace(PRE);
968 bool RenderThemeEfl::paintSearchField(const RenderObject& object, const PaintInfo& info, const IntRect& rect)
970 return paintThemePart(object, SearchField, info, rect);
973 void RenderThemeEfl::adjustInnerSpinButtonStyle(StyleResolver* styleResolver, RenderStyle* style, Element* element) const
975 if (!m_page && element && element->document().page()) {
976 static_cast<RenderThemeEfl&>(element->document().page()->theme()).adjustInnerSpinButtonStyle(styleResolver, style, element);
979 adjustSizeConstraints(style, Spinner);
982 bool RenderThemeEfl::paintInnerSpinButton(const RenderObject& object, const PaintInfo& info, const IntRect& rect)
984 return paintThemePart(object, Spinner, info, rect);
987 void RenderThemeEfl::setDefaultFontSize(int size)
989 defaultFontSize = size;
992 void RenderThemeEfl::systemFont(CSSValueID, FontDescription& fontDescription) const
994 // It was called by RenderEmbeddedObject::paintReplaced to render alternative string.
995 // To avoid cairo_error while rendering, fontDescription should be passed.
996 fontDescription.setOneFamily("Sans");
997 fontDescription.setSpecifiedSize(defaultFontSize);
998 fontDescription.setIsAbsoluteSize(true);
999 fontDescription.setGenericFamily(FontDescription::NoFamily);
1000 fontDescription.setWeight(FontWeightNormal);
1001 fontDescription.setItalic(false);
1004 void RenderThemeEfl::adjustProgressBarStyle(StyleResolver*, RenderStyle* style, Element*) const
1006 style->setBoxShadow(nullptr);
1009 double RenderThemeEfl::animationRepeatIntervalForProgressBar(RenderProgress*) const
1011 return progressAnimationInterval;
1014 double RenderThemeEfl::animationDurationForProgressBar(RenderProgress*) const
1016 return progressAnimationInterval * progressAnimationFrames * 2; // "2" for back and forth;
1019 bool RenderThemeEfl::paintProgressBar(const RenderObject& object, const PaintInfo& info, const IntRect& rect)
1021 if (!object.isProgress())
1024 return paintThemePart(object, ProgressBar, info, rect);
1028 String RenderThemeEfl::mediaControlsStyleSheet()
1030 return ASCIILiteral(mediaControlsAppleUserAgentStyleSheet);
1033 String RenderThemeEfl::mediaControlsScript()
1035 StringBuilder scriptBuilder;
1036 scriptBuilder.append(mediaControlsLocalizedStringsJavaScript, sizeof(mediaControlsLocalizedStringsJavaScript));
1037 scriptBuilder.append(mediaControlsAppleJavaScript, sizeof(mediaControlsAppleJavaScript));
1038 return scriptBuilder.toString();
1042 #undef _ASSERT_ON_RELEASE_RETURN
1043 #undef _ASSERT_ON_RELEASE_RETURN_VAL