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
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Library General Public
11 * License as published by the Free Software Foundation; either
12 * version 2 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Library General Public License for more details.
19 * You should have received a copy of the GNU Library General Public License
20 * along with this library; see the file COPYING.LIB. If not, write to
21 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22 * Boston, MA 02110-1301, USA.
27 #include "RenderThemeEfl.h"
29 #include "CSSValueKeywords.h"
30 #include "FileSystem.h"
32 #include "FrameView.h"
33 #include "GraphicsContext.h"
34 #include "HTMLInputElement.h"
35 #include "NotImplemented.h"
37 #include "PaintInfo.h"
38 #include "PlatformContextCairo.h"
39 #include "RenderBox.h"
40 #include "RenderObject.h"
41 #include "RenderProgress.h"
42 #include "RenderSlider.h"
43 #include "UserAgentStyleSheets.h"
45 #include <Ecore_Evas.h>
47 #include <wtf/text/CString.h>
48 #include <wtf/text/WTFString.h>
51 #include "HTMLMediaElement.h"
52 #include "HTMLNames.h"
53 #include "TimeRanges.h"
58 using namespace HTMLNames;
61 // TODO: change from object count to ecore_evas size (bytes)
62 // TODO: as objects are webpage/user defined and they can be very large.
63 #define RENDER_THEME_EFL_PART_CACHE_MAX 32
65 // Initialize default font size.
66 float RenderThemeEfl::defaultFontSize = 16.0f;
68 // Constants for progress tag animation.
69 // These values have been copied from RenderThemeGtk.cpp
70 static const int progressAnimationFrames = 10;
71 static const double progressAnimationInterval = 0.125;
73 static const int sliderThumbWidth = 12;
74 static const int sliderThumbHeight = 12;
76 static const int mediaSliderHeight = 14;
77 static const int mediaSliderThumbWidth = 12;
78 static const int mediaSliderThumbHeight = 12;
81 void RenderThemeEfl::adjustSizeConstraints(RenderStyle* style, FormType type) const
83 const struct ThemePartDesc* desc = m_partDescs + (size_t)type;
85 if (style->minWidth().isIntrinsicOrAuto())
86 style->setMinWidth(desc->min.width());
87 if (style->minHeight().isIntrinsicOrAuto())
88 style->setMinHeight(desc->min.height());
90 if (desc->max.width().value() > 0 && style->maxWidth().isIntrinsicOrAuto())
91 style->setMaxWidth(desc->max.width());
92 if (desc->max.height().value() > 0 && style->maxHeight().isIntrinsicOrAuto())
93 style->setMaxHeight(desc->max.height());
95 style->setPaddingTop(desc->padding.top());
96 style->setPaddingBottom(desc->padding.bottom());
97 style->setPaddingLeft(desc->padding.left());
98 style->setPaddingRight(desc->padding.right());
101 bool RenderThemeEfl::themePartCacheEntryReset(struct ThemePartCacheEntry* entry, FormType type)
103 const char *file, *group;
107 edje_object_file_get(m_edje, &file, 0);
108 group = edjeGroupFromFormType(type);
112 if (!edje_object_file_set(entry->o, file, group)) {
113 Edje_Load_Error err = edje_object_load_error_get(entry->o);
114 const char *errmsg = edje_load_error_str(err);
115 EINA_LOG_ERR("Could not load '%s' from theme %s: %s",
116 group, file, errmsg);
122 bool RenderThemeEfl::themePartCacheEntrySurfaceCreate(struct ThemePartCacheEntry* entry)
125 cairo_status_t status;
130 ecore_evas_geometry_get(entry->ee, 0, 0, &w, &h);
134 entry->surface = cairo_image_surface_create_for_data((unsigned char *)ecore_evas_buffer_pixels_get(entry->ee),
135 CAIRO_FORMAT_ARGB32, w, h, w * 4);
136 status = cairo_surface_status(entry->surface);
137 if (status != CAIRO_STATUS_SUCCESS) {
138 EINA_LOG_ERR("Could not create cairo surface: %s",
139 cairo_status_to_string(status));
146 bool RenderThemeEfl::isFormElementTooLargeToDisplay(const IntSize& elementSize)
148 // This limit of 20000 pixels is hardcoded inside edje -- anything above this size
149 // will be clipped. This value seems to be reasonable enough so that hardcoding it
150 // here won't be a problem.
151 static const int maxEdjeDimension = 20000;
153 return elementSize.width() > maxEdjeDimension || elementSize.height() > maxEdjeDimension;
156 // allocate a new entry and fill it with edje group
157 struct RenderThemeEfl::ThemePartCacheEntry* RenderThemeEfl::cacheThemePartNew(FormType type, const IntSize& size)
159 if (isFormElementTooLargeToDisplay(size)) {
160 EINA_LOG_ERR("cannot render an element of size %dx%d", size.width(), size.height());
164 ThemePartCacheEntry* entry = new ThemePartCacheEntry;
166 EINA_LOG_ERR("could not allocate ThemePartCacheEntry.");
170 entry->ee = ecore_evas_buffer_new(size.width(), size.height());
172 EINA_LOG_ERR("ecore_evas_buffer_new(%d, %d) failed.",
173 size.width(), size.height());
178 entry->o = edje_object_add(ecore_evas_get(entry->ee));
180 if (!themePartCacheEntryReset(entry, type)) {
181 evas_object_del(entry->o);
182 ecore_evas_free(entry->ee);
187 if (!themePartCacheEntrySurfaceCreate(entry)) {
188 evas_object_del(entry->o);
189 ecore_evas_free(entry->ee);
194 evas_object_resize(entry->o, size.width(), size.height());
195 evas_object_show(entry->o);
200 m_partCache.prepend(entry);
204 // just change the edje group and return the same entry
205 struct RenderThemeEfl::ThemePartCacheEntry* RenderThemeEfl::cacheThemePartReset(FormType type, struct RenderThemeEfl::ThemePartCacheEntry* entry)
207 if (!themePartCacheEntryReset(entry, type)) {
208 entry->type = FormTypeLast; // invalidate
209 m_partCache.append(entry);
213 m_partCache.prepend(entry);
217 // resize entry and reset it
218 struct RenderThemeEfl::ThemePartCacheEntry* RenderThemeEfl::cacheThemePartResizeAndReset(FormType type, const IntSize& size, struct RenderThemeEfl::ThemePartCacheEntry* entry)
220 cairo_surface_finish(entry->surface);
221 ecore_evas_resize(entry->ee, size.width(), size.height());
222 evas_object_resize(entry->o, size.width(), size.height());
224 if (!themePartCacheEntrySurfaceCreate(entry)) {
225 evas_object_del(entry->o);
226 ecore_evas_free(entry->ee);
231 return cacheThemePartReset(type, entry);
234 // general purpose get (will create, reuse and all)
235 struct RenderThemeEfl::ThemePartCacheEntry* RenderThemeEfl::cacheThemePartGet(FormType type, const IntSize& size)
237 Vector<struct ThemePartCacheEntry *>::iterator itr, end;
238 struct ThemePartCacheEntry *ce_last_size = 0;
239 int i, idxLastSize = -1;
241 itr = m_partCache.begin();
242 end = m_partCache.end();
243 for (i = 0; itr != end; i++, itr++) {
244 struct ThemePartCacheEntry *entry = *itr;
245 if (entry->size == size) {
246 if (entry->type == type)
248 ce_last_size = entry;
253 if (m_partCache.size() < RENDER_THEME_EFL_PART_CACHE_MAX)
254 return cacheThemePartNew(type, size);
256 if (ce_last_size && ce_last_size != m_partCache.first()) {
257 m_partCache.remove(idxLastSize);
258 return cacheThemePartReset(type, ce_last_size);
261 ThemePartCacheEntry* entry = m_partCache.last();
262 m_partCache.removeLast();
263 return cacheThemePartResizeAndReset(type, size, entry);
266 void RenderThemeEfl::cacheThemePartFlush()
268 Vector<struct ThemePartCacheEntry *>::iterator itr, end;
270 itr = m_partCache.begin();
271 end = m_partCache.end();
272 for (; itr != end; itr++) {
273 struct ThemePartCacheEntry *entry = *itr;
274 cairo_surface_finish(entry->surface);
275 evas_object_del(entry->o);
276 ecore_evas_free(entry->ee);
282 void RenderThemeEfl::applyEdjeStateFromForm(Evas_Object* object, ControlStates states)
284 const char *signals[] = { // keep in sync with WebCore/platform/ThemeTypes.h
296 edje_object_signal_emit(object, "reset", "");
298 for (size_t i = 0; i < WTF_ARRAY_LENGTH(signals); ++i) {
299 if (states & (1 << i))
300 edje_object_signal_emit(object, signals[i], "");
304 bool RenderThemeEfl::paintThemePart(RenderObject* object, FormType type, const PaintInfo& info, const IntRect& rect)
306 ThemePartCacheEntry* entry;
313 entry = cacheThemePartGet(type, rect.size());
317 applyEdjeStateFromForm(entry->o, controlStatesForRenderer(object));
319 cairo = info.context->platformContext()->cr();
322 // Currently, only sliders needs this message; if other widget ever needs special
323 // treatment, move them to special functions.
324 if (type == SliderVertical || type == SliderHorizontal) {
325 RenderSlider* renderSlider = toRenderSlider(object);
326 HTMLInputElement* input = renderSlider->node()->toInputElement();
327 Edje_Message_Float_Set* msg;
328 double valueRange = input->maximum() - input->minimum();
330 msg = static_cast<Edje_Message_Float_Set*>(alloca(sizeof(Edje_Message_Float_Set) + sizeof(float)));
333 msg->val[0] = static_cast<float>((input->valueAsNumber() - input->minimum()) / valueRange);
337 edje_object_message_send(entry->o, EDJE_MESSAGE_FLOAT_SET, 0, msg);
338 #if ENABLE(PROGRESS_TAG)
339 } else if (type == ProgressBar) {
340 RenderProgress* renderProgress = toRenderProgress(object);
341 Edje_Message_Float_Set* msg;
345 msg = static_cast<Edje_Message_Float_Set*>(alloca(sizeof(Edje_Message_Float_Set) + sizeof(float)));
347 value = renderProgress->position();
350 if (object->style()->direction() == RTL)
351 msg->val[0] = (1.0 - value) * max;
355 edje_object_message_send(entry->o, EDJE_MESSAGE_FLOAT_SET, 0, msg);
359 edje_object_calc_force(entry->o);
360 edje_object_message_signal_process(entry->o);
361 updates = evas_render_updates(ecore_evas_get(entry->ee));
362 evas_render_updates_free(updates);
365 cairo_set_source_surface(cairo, entry->surface, rect.x(), rect.y());
366 cairo_paint_with_alpha(cairo, 1.0);
367 cairo_restore(cairo);
372 PassRefPtr<RenderTheme> RenderThemeEfl::create(Page* page)
374 return adoptRef(new RenderThemeEfl(page));
377 PassRefPtr<RenderTheme> RenderTheme::themeForPage(Page* page)
380 return RenderThemeEfl::create(page);
382 static RenderTheme* fallback = RenderThemeEfl::create(0).releaseRef();
386 static void renderThemeEflColorClassSelectionActive(void* data, Evas_Object* object, const char* signal, const char* source)
388 RenderThemeEfl* that = static_cast<RenderThemeEfl *>(data);
389 int fr, fg, fb, fa, br, bg, bb, ba;
391 if (!edje_object_color_class_get(object, source, &fr, &fg, &fb, &fa, &br, &bg, &bb, &ba, 0, 0, 0, 0))
394 that->setActiveSelectionColor(fr, fg, fb, fa, br, bg, bb, ba);
397 static void renderThemeEflColorClassSelectionInactive(void* data, Evas_Object* object, const char* signal, const char* source)
399 RenderThemeEfl* that = static_cast<RenderThemeEfl *>(data);
400 int fr, fg, fb, fa, br, bg, bb, ba;
402 if (!edje_object_color_class_get(object, source, &fr, &fg, &fb, &fa, &br, &bg, &bb, &ba, 0, 0, 0, 0))
405 that->setInactiveSelectionColor(fr, fg, fb, fa, br, bg, bb, ba);
408 static void renderThemeEflColorClassFocusRing(void* data, Evas_Object* object, const char* signal, const char* source)
410 RenderThemeEfl* that = static_cast<RenderThemeEfl *>(data);
413 if (!edje_object_color_class_get(object, source, &fr, &fg, &fb, &fa, 0, 0, 0, 0, 0, 0, 0, 0))
416 that->setFocusRingColor(fr, fg, fb, fa);
419 static void renderThemeEflColorClassButtonText(void* data, Evas_Object* object, const char* signal, const char* source)
421 RenderThemeEfl* that = static_cast<RenderThemeEfl *>(data);
422 int fr, fg, fb, fa, br, bg, bb, ba;
424 if (!edje_object_color_class_get(object, source, &fr, &fg, &fb, &fa, &br, &bg, &bb, &ba, 0, 0, 0, 0))
427 that->setButtonTextColor(fr, fg, fb, fa, br, bg, bb, ba);
430 static void renderThemeEflColorClassComboText(void* data, Evas_Object* object, const char* signal, const char* source)
432 RenderThemeEfl* that = static_cast<RenderThemeEfl *>(data);
433 int fr, fg, fb, fa, br, bg, bb, ba;
435 if (!edje_object_color_class_get(object, source, &fr, &fg, &fb, &fa, &br, &bg, &bb, &ba, 0, 0, 0, 0))
438 that->setComboTextColor(fr, fg, fb, fa, br, bg, bb, ba);
441 static void renderThemeEflColorClassEntryText(void* data, Evas_Object* object, const char* signal, const char* source)
443 RenderThemeEfl* that = static_cast<RenderThemeEfl *>(data);
444 int fr, fg, fb, fa, br, bg, bb, ba;
446 if (!edje_object_color_class_get(object, source, &fr, &fg, &fb, &fa, &br, &bg, &bb, &ba, 0, 0, 0, 0))
449 that->setEntryTextColor(fr, fg, fb, fa, br, bg, bb, ba);
452 static void renderThemeEflColorClassSearchText(void* data, Evas_Object* object, const char* signal, const char* source)
454 RenderThemeEfl* that = static_cast<RenderThemeEfl *>(data);
455 int fr, fg, fb, fa, br, bg, bb, ba;
456 if (!edje_object_color_class_get(object, source, &fr, &fg, &fb, &fa, &br, &bg, &bb, &ba, 0, 0, 0, 0))
459 that->setSearchTextColor(fr, fg, fb, fa, br, bg, bb, ba);
462 void RenderThemeEfl::createCanvas()
465 m_canvas = ecore_evas_buffer_new(1, 1);
469 void RenderThemeEfl::createEdje()
472 Frame* frame = m_page ? m_page->mainFrame() : 0;
473 FrameView* view = frame ? frame->view() : 0;
474 String theme = view ? view->edjeThemeRecursive() : "";
476 EINA_LOG_ERR("No theme defined, unable to set RenderThemeEfl.");
478 m_edje = edje_object_add(ecore_evas_get(m_canvas));
480 EINA_LOG_ERR("Could not create base edje object.");
481 else if (!edje_object_file_set(m_edje, theme.utf8().data(), "webkit/base")) {
482 Edje_Load_Error err = edje_object_load_error_get(m_edje);
483 const char* errmsg = edje_load_error_str(err);
484 EINA_LOG_ERR("Could not load 'webkit/base' from theme %s: %s",
485 theme.utf8().data(), errmsg);
486 evas_object_del(m_edje);
489 #define CONNECT(cc, func) \
490 edje_object_signal_callback_add(m_edje, "color_class,set", \
491 "webkit/"cc, func, this)
493 CONNECT("selection/active",
494 renderThemeEflColorClassSelectionActive);
495 CONNECT("selection/inactive",
496 renderThemeEflColorClassSelectionInactive);
497 CONNECT("focus_ring", renderThemeEflColorClassFocusRing);
498 CONNECT("button/text", renderThemeEflColorClassButtonText);
499 CONNECT("combo/text", renderThemeEflColorClassComboText);
500 CONNECT("entry/text", renderThemeEflColorClassEntryText);
501 CONNECT("search/text", renderThemeEflColorClassSearchText);
508 void RenderThemeEfl::applyEdjeColors()
510 int fr, fg, fb, fa, br, bg, bb, ba;
512 #define COLOR_GET(cls) \
513 edje_object_color_class_get(m_edje, "webkit/"cls, \
514 &fr, &fg, &fb, &fa, &br, &bg, &bb, &ba, \
517 if (COLOR_GET("selection/active")) {
518 m_activeSelectionForegroundColor = Color(fr, fg, fb, fa);
519 m_activeSelectionBackgroundColor = Color(br, bg, bb, ba);
521 if (COLOR_GET("selection/inactive")) {
522 m_inactiveSelectionForegroundColor = Color(fr, fg, fb, fa);
523 m_inactiveSelectionBackgroundColor = Color(br, bg, bb, ba);
525 if (COLOR_GET("focus_ring")) {
526 m_focusRingColor = Color(fr, fg, fb, fa);
527 // webkit just use platformFocusRingColor() for default theme (without page)
528 // this is ugly, but no other way to do it unless we change
529 // it to use page themes as much as possible.
530 RenderTheme::setCustomFocusRingColor(m_focusRingColor);
532 if (COLOR_GET("button/text")) {
533 m_buttonTextForegroundColor = Color(fr, fg, fb, fa);
534 m_buttonTextBackgroundColor = Color(br, bg, bb, ba);
536 if (COLOR_GET("combo/text")) {
537 m_comboTextForegroundColor = Color(fr, fg, fb, fa);
538 m_comboTextBackgroundColor = Color(br, bg, bb, ba);
540 if (COLOR_GET("entry/text")) {
541 m_entryTextForegroundColor = Color(fr, fg, fb, fa);
542 m_entryTextBackgroundColor = Color(br, bg, bb, ba);
544 if (COLOR_GET("search/text")) {
545 m_searchTextForegroundColor = Color(fr, fg, fb, fa);
546 m_searchTextBackgroundColor = Color(br, bg, bb, ba);
549 platformColorsDidChange();
552 void RenderThemeEfl::applyPartDescriptionFallback(struct ThemePartDesc* desc)
554 desc->min.setWidth(Length(0, Fixed));
555 desc->min.setHeight(Length(0, Fixed));
557 desc->max.setWidth(Length(0, Fixed));
558 desc->max.setHeight(Length(0, Fixed));
560 desc->padding = LengthBox(0, 0, 0, 0);
563 void RenderThemeEfl::applyPartDescription(Evas_Object* object, struct ThemePartDesc* desc)
565 Evas_Coord minw, minh, maxw, maxh;
567 edje_object_size_min_get(object, &minw, &minh);
569 edje_object_size_min_calc(object, &minw, &minh);
571 desc->min.setWidth(Length(minw, Fixed));
572 desc->min.setHeight(Length(minh, Fixed));
574 edje_object_size_max_get(object, &maxw, &maxh);
575 desc->max.setWidth(Length(maxw, Fixed));
576 desc->max.setHeight(Length(maxh, Fixed));
578 if (!edje_object_part_exists(object, "text_confinement"))
579 desc->padding = LengthBox(0, 0, 0, 0);
581 Evas_Coord px, py, pw, ph;
582 Evas_Coord ox = 0, oy = 0, ow = 0, oh = 0;
593 if (maxw > 0 && ow > maxw)
595 if (maxh > 0 && oh > maxh)
598 evas_object_move(object, ox, oy);
599 evas_object_resize(object, ow, oh);
600 edje_object_calc_force(object);
601 edje_object_message_signal_process(object);
602 edje_object_part_geometry_get(object, "text_confinement", &px, &py, &pw, &ph);
605 b = (oh + oy) - (ph + py);
608 r = (ow + ox) - (pw + px);
610 desc->padding = LengthBox(t, r, b, l);
614 const char* RenderThemeEfl::edjeGroupFromFormType(FormType type) const
616 static const char* groups[] = {
617 #define W(n) "webkit/widget/"n
623 #if ENABLE(PROGRESS_TAG)
627 W("search/decoration"),
628 W("search/results_button"),
629 W("search/results_decoration"),
630 W("search/cancel_button"),
631 W("slider/vertical"),
632 W("slider/horizontal"),
634 W("mediacontrol/playpause_button"),
635 W("mediacontrol/mute_button"),
636 W("mediacontrol/seekforward_button"),
637 W("mediacontrol/seekbackward_button"),
638 W("mediacontrol/fullscreen_button"),
644 ASSERT((size_t)type < sizeof(groups) / sizeof(groups[0])); // out of sync?
648 void RenderThemeEfl::applyPartDescriptions()
657 edje_object_file_get(m_edje, &file, 0);
660 object = edje_object_add(ecore_evas_get(m_canvas));
662 EINA_LOG_ERR("Could not create Edje object.");
666 for (i = 0; i < FormTypeLast; i++) {
667 FormType type = static_cast<FormType>(i);
668 const char* group = edjeGroupFromFormType(type);
669 m_partDescs[i].type = type;
670 if (!edje_object_file_set(object, file, group)) {
671 Edje_Load_Error err = edje_object_load_error_get(object);
672 const char* errmsg = edje_load_error_str(err);
673 EINA_LOG_ERR("Could not set theme group '%s' of file '%s': %s",
674 group, file, errmsg);
676 applyPartDescriptionFallback(m_partDescs + i);
678 applyPartDescription(object, m_partDescs + i);
680 evas_object_del(object);
683 void RenderThemeEfl::themeChanged()
685 cacheThemePartFlush();
700 applyPartDescriptions();
703 RenderThemeEfl::RenderThemeEfl(Page* page)
706 , m_activeSelectionBackgroundColor(0, 0, 255)
707 , m_activeSelectionForegroundColor(Color::white)
708 , m_inactiveSelectionBackgroundColor(0, 0, 128)
709 , m_inactiveSelectionForegroundColor(200, 200, 200)
710 , m_focusRingColor(32, 32, 224, 224)
711 , m_buttonTextBackgroundColor(0, 0, 0, 0)
712 , m_buttonTextForegroundColor(Color::black)
713 , m_comboTextBackgroundColor(0, 0, 0, 0)
714 , m_comboTextForegroundColor(Color::black)
715 , m_entryTextBackgroundColor(0, 0, 0, 0)
716 , m_entryTextForegroundColor(Color::black)
717 , m_searchTextBackgroundColor(0, 0, 0, 0)
718 , m_searchTextForegroundColor(Color::black)
719 , m_sliderThumbColor(Color::darkGray)
721 , m_mediaPanelColor(220, 220, 195) // light tannish color.
722 , m_mediaSliderColor(Color::white)
727 if (page && page->mainFrame() && page->mainFrame()->view())
731 RenderThemeEfl::~RenderThemeEfl()
733 cacheThemePartFlush();
737 evas_object_del(m_edje);
738 ecore_evas_free(m_canvas);
742 void RenderThemeEfl::setActiveSelectionColor(int foreR, int foreG, int foreB, int foreA, int backR, int backG, int backB, int backA)
744 m_activeSelectionForegroundColor = Color(foreR, foreG, foreB, foreA);
745 m_activeSelectionBackgroundColor = Color(backR, backG, backB, backA);
746 platformColorsDidChange();
749 void RenderThemeEfl::setInactiveSelectionColor(int foreR, int foreG, int foreB, int foreA, int backR, int backG, int backB, int backA)
751 m_inactiveSelectionForegroundColor = Color(foreR, foreG, foreB, foreA);
752 m_inactiveSelectionBackgroundColor = Color(backR, backG, backB, backA);
753 platformColorsDidChange();
756 void RenderThemeEfl::setFocusRingColor(int r, int g, int b, int a)
758 m_focusRingColor = Color(r, g, b, a);
759 // webkit just use platformFocusRingColor() for default theme (without page)
760 // this is ugly, but no other way to do it unless we change
761 // it to use page themes as much as possible.
762 RenderTheme::setCustomFocusRingColor(m_focusRingColor);
763 platformColorsDidChange();
766 void RenderThemeEfl::setButtonTextColor(int foreR, int foreG, int foreB, int foreA, int backR, int backG, int backB, int backA)
768 m_buttonTextForegroundColor = Color(foreR, foreG, foreB, foreA);
769 m_buttonTextBackgroundColor = Color(backR, backG, backB, backA);
770 platformColorsDidChange();
773 void RenderThemeEfl::setComboTextColor(int foreR, int foreG, int foreB, int foreA, int backR, int backG, int backB, int backA)
775 m_comboTextForegroundColor = Color(foreR, foreG, foreB, foreA);
776 m_comboTextBackgroundColor = Color(backR, backG, backB, backA);
777 platformColorsDidChange();
780 void RenderThemeEfl::setEntryTextColor(int foreR, int foreG, int foreB, int foreA, int backR, int backG, int backB, int backA)
782 m_entryTextForegroundColor = Color(foreR, foreG, foreB, foreA);
783 m_entryTextBackgroundColor = Color(backR, backG, backB, backA);
784 platformColorsDidChange();
787 void RenderThemeEfl::setSearchTextColor(int foreR, int foreG, int foreB, int foreA, int backR, int backG, int backB, int backA)
789 m_searchTextForegroundColor = Color(foreR, foreG, foreB, foreA);
790 m_searchTextBackgroundColor = Color(backR, backG, backB, backA);
791 platformColorsDidChange();
794 static bool supportsFocus(ControlPart appearance)
796 switch (appearance) {
801 case SearchFieldPart:
805 case SliderVerticalPart:
806 case SliderHorizontalPart:
813 bool RenderThemeEfl::supportsFocusRing(const RenderStyle* style) const
815 return supportsFocus(style->appearance());
818 bool RenderThemeEfl::controlSupportsTints(const RenderObject* object) const
820 return isEnabled(object);
823 int RenderThemeEfl::baselinePosition(const RenderObject* object) const
825 if (!object->isBox())
828 if (object->style()->appearance() == CheckboxPart
829 || object->style()->appearance() == RadioPart)
830 return toRenderBox(object)->marginTop() + toRenderBox(object)->height() - 3;
832 return RenderTheme::baselinePosition(object);
835 bool RenderThemeEfl::paintSliderTrack(RenderObject* object, const PaintInfo& info, const IntRect& rect)
837 if (object->style()->appearance() == SliderHorizontalPart)
838 return paintThemePart(object, SliderHorizontal, info, rect);
839 return paintThemePart(object, SliderVertical, info, rect);
842 void RenderThemeEfl::adjustSliderTrackStyle(CSSStyleSelector* selector, RenderStyle* style, Element* element) const
844 if (!m_page && element && element->document()->page()) {
845 static_cast<RenderThemeEfl*>(element->document()->page()->theme())->adjustSliderTrackStyle(selector, style, element);
849 adjustSizeConstraints(style, SliderHorizontal);
850 style->resetBorder();
852 const struct ThemePartDesc *desc = m_partDescs + (size_t)SliderHorizontal;
853 if (style->width().value() < desc->min.width().value())
854 style->setWidth(desc->min.width());
855 if (style->height().value() < desc->min.height().value())
856 style->setHeight(desc->min.height());
859 void RenderThemeEfl::adjustSliderThumbStyle(CSSStyleSelector* selector, RenderStyle* style, Element* element) const
861 RenderTheme::adjustSliderThumbStyle(selector, style, element);
862 adjustSliderTrackStyle(selector, style, element);
865 void RenderThemeEfl::adjustSliderThumbSize(RenderStyle* style) const
867 ControlPart part = style->appearance();
868 if (part == SliderThumbVerticalPart || part == SliderThumbHorizontalPart) {
869 style->setWidth(Length(sliderThumbHeight, Fixed));
870 style->setHeight(Length(sliderThumbWidth, Fixed));
873 else if (part == MediaSliderThumbPart) {
874 style->setWidth(Length(mediaSliderThumbWidth, Fixed));
875 style->setHeight(Length(mediaSliderThumbHeight, Fixed));
880 bool RenderThemeEfl::paintSliderThumb(RenderObject* object, const PaintInfo& info, const IntRect& rect)
882 // We've already painted it in paintSliderTrack(), no need to do anything here.
886 void RenderThemeEfl::adjustCheckboxStyle(CSSStyleSelector* selector, RenderStyle* style, Element* element) const
888 if (!m_page && element && element->document()->page()) {
889 static_cast<RenderThemeEfl*>(element->document()->page()->theme())->adjustCheckboxStyle(selector, style, element);
892 adjustSizeConstraints(style, CheckBox);
893 style->resetBorder();
895 const struct ThemePartDesc *desc = m_partDescs + (size_t)CheckBox;
896 if (style->width().value() < desc->min.width().value())
897 style->setWidth(desc->min.width());
898 if (style->height().value() < desc->min.height().value())
899 style->setHeight(desc->min.height());
902 bool RenderThemeEfl::paintCheckbox(RenderObject* object, const PaintInfo& info, const IntRect& rect)
904 return paintThemePart(object, CheckBox, info, rect);
907 void RenderThemeEfl::adjustRadioStyle(CSSStyleSelector* selector, RenderStyle* style, Element* element) const
909 if (!m_page && element && element->document()->page()) {
910 static_cast<RenderThemeEfl*>(element->document()->page()->theme())->adjustRadioStyle(selector, style, element);
913 adjustSizeConstraints(style, RadioButton);
914 style->resetBorder();
916 const struct ThemePartDesc *desc = m_partDescs + (size_t)RadioButton;
917 if (style->width().value() < desc->min.width().value())
918 style->setWidth(desc->min.width());
919 if (style->height().value() < desc->min.height().value())
920 style->setHeight(desc->min.height());
923 bool RenderThemeEfl::paintRadio(RenderObject* object, const PaintInfo& info, const IntRect& rect)
925 return paintThemePart(object, RadioButton, info, rect);
928 void RenderThemeEfl::adjustButtonStyle(CSSStyleSelector* selector, RenderStyle* style, Element* element) const
930 if (!m_page && element && element->document()->page()) {
931 static_cast<RenderThemeEfl*>(element->document()->page()->theme())->adjustButtonStyle(selector, style, element);
935 adjustSizeConstraints(style, Button);
937 if (style->appearance() == PushButtonPart) {
938 style->resetBorder();
939 style->setWhiteSpace(PRE);
940 style->setHeight(Length(Auto));
941 style->setColor(m_buttonTextForegroundColor);
942 style->setBackgroundColor(m_buttonTextBackgroundColor);
946 bool RenderThemeEfl::paintButton(RenderObject* object, const PaintInfo& info, const IntRect& rect)
948 return paintThemePart(object, Button, info, rect);
951 void RenderThemeEfl::adjustMenuListStyle(CSSStyleSelector* selector, RenderStyle* style, Element* element) const
953 if (!m_page && element && element->document()->page()) {
954 static_cast<RenderThemeEfl*>(element->document()->page()->theme())->adjustMenuListStyle(selector, style, element);
957 adjustSizeConstraints(style, ComboBox);
958 style->resetBorder();
959 style->setWhiteSpace(PRE);
960 style->setColor(m_comboTextForegroundColor);
961 style->setBackgroundColor(m_comboTextBackgroundColor);
964 bool RenderThemeEfl::paintMenuList(RenderObject* object, const PaintInfo& info, const IntRect& rect)
966 return paintThemePart(object, ComboBox, info, rect);
969 void RenderThemeEfl::adjustMenuListButtonStyle(CSSStyleSelector* selector, RenderStyle* style, Element* element) const
971 adjustMenuListStyle(selector, style, element);
974 bool RenderThemeEfl::paintMenuListButton(RenderObject* object, const PaintInfo& info, const IntRect& rect)
976 return paintMenuList(object, info, rect);
979 void RenderThemeEfl::adjustTextFieldStyle(CSSStyleSelector* selector, RenderStyle* style, Element* element) const
981 if (!m_page && element && element->document()->page()) {
982 static_cast<RenderThemeEfl*>(element->document()->page()->theme())->adjustTextFieldStyle(selector, style, element);
985 adjustSizeConstraints(style, TextField);
986 style->resetBorder();
987 style->setWhiteSpace(PRE);
988 style->setColor(m_entryTextForegroundColor);
989 style->setBackgroundColor(m_entryTextBackgroundColor);
992 bool RenderThemeEfl::paintTextField(RenderObject* object, const PaintInfo& info, const IntRect& rect)
994 return paintThemePart(object, TextField, info, rect);
997 void RenderThemeEfl::adjustTextAreaStyle(CSSStyleSelector* selector, RenderStyle* style, Element* element) const
999 adjustTextFieldStyle(selector, style, element);
1002 bool RenderThemeEfl::paintTextArea(RenderObject* object, const PaintInfo& info, const IntRect& rect)
1004 return paintTextField(object, info, rect);
1007 void RenderThemeEfl::adjustSearchFieldDecorationStyle(CSSStyleSelector* selector, RenderStyle* style, Element* element) const
1009 if (!m_page && element && element->document()->page()) {
1010 static_cast<RenderThemeEfl*>(element->document()->page()->theme())->adjustSearchFieldDecorationStyle(selector, style, element);
1013 adjustSizeConstraints(style, SearchFieldDecoration);
1014 style->resetBorder();
1015 style->setWhiteSpace(PRE);
1018 bool RenderThemeEfl::paintSearchFieldDecoration(RenderObject* object, const PaintInfo& info, const IntRect& rect)
1020 return paintThemePart(object, SearchFieldDecoration, info, rect);
1023 void RenderThemeEfl::adjustSearchFieldResultsButtonStyle(CSSStyleSelector* selector, RenderStyle* style, Element* element) const
1025 if (!m_page && element && element->document()->page()) {
1026 static_cast<RenderThemeEfl*>(element->document()->page()->theme())->adjustSearchFieldResultsButtonStyle(selector, style, element);
1029 adjustSizeConstraints(style, SearchFieldResultsButton);
1030 style->resetBorder();
1031 style->setWhiteSpace(PRE);
1034 bool RenderThemeEfl::paintSearchFieldResultsButton(RenderObject* object, const PaintInfo& info, const IntRect& rect)
1036 return paintThemePart(object, SearchFieldResultsButton, info, rect);
1039 void RenderThemeEfl::adjustSearchFieldResultsDecorationStyle(CSSStyleSelector* selector, RenderStyle* style, Element* element) const
1041 if (!m_page && element && element->document()->page()) {
1042 static_cast<RenderThemeEfl*>(element->document()->page()->theme())->adjustSearchFieldResultsDecorationStyle(selector, style, element);
1045 adjustSizeConstraints(style, SearchFieldResultsDecoration);
1046 style->resetBorder();
1047 style->setWhiteSpace(PRE);
1050 bool RenderThemeEfl::paintSearchFieldResultsDecoration(RenderObject* object, const PaintInfo& info, const IntRect& rect)
1052 return paintThemePart(object, SearchFieldResultsDecoration, info, rect);
1055 void RenderThemeEfl::adjustSearchFieldCancelButtonStyle(CSSStyleSelector* selector, RenderStyle* style, Element* element) const
1057 if (!m_page && element && element->document()->page()) {
1058 static_cast<RenderThemeEfl*>(element->document()->page()->theme())->adjustSearchFieldCancelButtonStyle(selector, style, element);
1061 adjustSizeConstraints(style, SearchFieldCancelButton);
1062 style->resetBorder();
1063 style->setWhiteSpace(PRE);
1066 bool RenderThemeEfl::paintSearchFieldCancelButton(RenderObject* object, const PaintInfo& info, const IntRect& rect)
1068 return paintThemePart(object, SearchFieldCancelButton, info, rect);
1071 void RenderThemeEfl::adjustSearchFieldStyle(CSSStyleSelector* selector, RenderStyle* style, Element* element) const
1073 if (!m_page && element && element->document()->page()) {
1074 static_cast<RenderThemeEfl*>(element->document()->page()->theme())->adjustSearchFieldStyle(selector, style, element);
1077 adjustSizeConstraints(style, SearchField);
1078 style->resetBorder();
1079 style->setWhiteSpace(PRE);
1080 style->setColor(m_searchTextForegroundColor);
1081 style->setBackgroundColor(m_searchTextBackgroundColor);
1084 bool RenderThemeEfl::paintSearchField(RenderObject* object, const PaintInfo& info, const IntRect& rect)
1086 return paintThemePart(object, SearchField, info, rect);
1089 void RenderThemeEfl::setDefaultFontSize(int size)
1091 defaultFontSize = size;
1094 void RenderThemeEfl::systemFont(int propId, FontDescription& fontDescription) const
1096 // It was called by RenderEmbeddedObject::paintReplaced to render alternative string.
1097 // To avoid cairo_error while rendering, fontDescription should be passed.
1098 DEFINE_STATIC_LOCAL(String, fontFace, ("Sans"));
1099 float fontSize = defaultFontSize;
1101 fontDescription.firstFamily().setFamily(fontFace);
1102 fontDescription.setSpecifiedSize(fontSize);
1103 fontDescription.setIsAbsoluteSize(true);
1104 fontDescription.setGenericFamily(FontDescription::NoFamily);
1105 fontDescription.setWeight(FontWeightNormal);
1106 fontDescription.setItalic(false);
1109 #if ENABLE(PROGRESS_TAG)
1110 void RenderThemeEfl::adjustProgressBarStyle(CSSStyleSelector* selector, RenderStyle* style, Element* element) const
1112 style->setBoxShadow(nullptr);
1115 double RenderThemeEfl::animationRepeatIntervalForProgressBar(RenderProgress*) const
1117 return progressAnimationInterval;
1120 double RenderThemeEfl::animationDurationForProgressBar(RenderProgress*) const
1122 return progressAnimationInterval * progressAnimationFrames * 2; // "2" for back and forth;
1125 bool RenderThemeEfl::paintProgressBar(RenderObject* object, const PaintInfo& info, const IntRect& rect)
1127 return paintThemePart(object, ProgressBar, info, rect);
1132 bool RenderThemeEfl::emitMediaButtonSignal(FormType formType, MediaControlElementType mediaElementType, const IntRect& rect)
1134 ThemePartCacheEntry* entry;
1136 entry = cacheThemePartGet(formType, rect.size());
1141 if (mediaElementType == MediaPlayButton)
1142 edje_object_signal_emit(entry->o, "play", "");
1143 else if (mediaElementType == MediaPauseButton)
1144 edje_object_signal_emit(entry->o, "pause", "");
1145 else if (mediaElementType == MediaMuteButton)
1146 edje_object_signal_emit(entry->o, "mute", "");
1147 else if (mediaElementType == MediaUnMuteButton)
1148 edje_object_signal_emit(entry->o, "sound", "");
1149 else if (mediaElementType == MediaSeekForwardButton)
1150 edje_object_signal_emit(entry->o, "seekforward", "");
1151 else if (mediaElementType == MediaSeekBackButton)
1152 edje_object_signal_emit(entry->o, "seekbackward", "");
1153 else if (mediaElementType == MediaFullscreenButton)
1154 edje_object_signal_emit(entry->o, "fullscreen", "");
1161 String RenderThemeEfl::extraMediaControlsStyleSheet()
1163 return String(mediaControlsEflUserAgentStyleSheet, sizeof(mediaControlsEflUserAgentStyleSheet));
1166 String RenderThemeEfl::formatMediaControlsCurrentTime(float currentTime, float duration) const
1168 return formatMediaControlsTime(currentTime) + " / " + formatMediaControlsTime(duration);
1171 bool RenderThemeEfl::paintMediaFullscreenButton(RenderObject* object, const PaintInfo& info, const IntRect& rect)
1173 Node* mediaNode = object->node() ? object->node()->shadowAncestorNode() : 0;
1174 if (!mediaNode || (!mediaNode->hasTagName(videoTag)))
1177 if (!emitMediaButtonSignal(FullScreenButton, MediaFullscreenButton, rect))
1180 return paintThemePart(object, FullScreenButton, info, rect);
1183 bool RenderThemeEfl::paintMediaMuteButton(RenderObject* object, const PaintInfo& info, const IntRect& rect)
1185 Node* mediaNode = object->node() ? object->node()->shadowAncestorNode() : 0;
1186 if (!mediaNode || !mediaNode->isElementNode() || !static_cast<Element*>(mediaNode)->isMediaElement())
1189 HTMLMediaElement* mediaElement = static_cast<HTMLMediaElement*>(mediaNode);
1191 if (!emitMediaButtonSignal(MuteUnMuteButton, mediaElement->muted() ? MediaMuteButton : MediaUnMuteButton, rect))
1194 return paintThemePart(object, MuteUnMuteButton, info, rect);
1197 bool RenderThemeEfl::paintMediaPlayButton(RenderObject* object, const PaintInfo& info, const IntRect& rect)
1199 Node* node = object->node();
1200 if (!node || !node->isMediaControlElement())
1203 MediaControlPlayButtonElement* button = static_cast<MediaControlPlayButtonElement*>(node);
1204 if (!emitMediaButtonSignal(PlayPauseButton, button->displayType(), rect))
1207 return paintThemePart(object, PlayPauseButton, info, rect);
1210 bool RenderThemeEfl::paintMediaSeekBackButton(RenderObject* object, const PaintInfo& info, const IntRect& rect)
1212 Node* node = object->node();
1213 if (!node || !node->isMediaControlElement())
1216 MediaControlSeekButtonElement* button = static_cast<MediaControlSeekButtonElement*>(node);
1217 if (!emitMediaButtonSignal(SeekBackwardButton, button->displayType(), rect))
1220 return paintThemePart(object, SeekBackwardButton, info, rect);
1223 bool RenderThemeEfl::paintMediaSeekForwardButton(RenderObject* object, const PaintInfo& info, const IntRect& rect)
1225 Node* node = object->node();
1226 if (!node || !node->isMediaControlElement())
1229 MediaControlSeekButtonElement* button = static_cast<MediaControlSeekButtonElement*>(node);
1230 if (!emitMediaButtonSignal(SeekForwardButton, button->displayType(), rect))
1233 return paintThemePart(object, SeekForwardButton, info, rect);
1236 bool RenderThemeEfl::paintMediaSliderTrack(RenderObject* object, const PaintInfo& info, const IntRect& rect)
1238 GraphicsContext* context = info.context;
1240 context->fillRect(FloatRect(rect), m_mediaPanelColor, ColorSpaceDeviceRGB);
1241 context->fillRect(FloatRect(IntRect(rect.x(), rect.y() + (rect.height() - mediaSliderHeight) / 2,
1242 rect.width(), mediaSliderHeight)), m_mediaSliderColor, ColorSpaceDeviceRGB);
1244 RenderStyle* style = object->style();
1245 HTMLMediaElement* mediaElement = toParentMediaElement(object);
1250 // Draw the buffered ranges. This code is highly inspired from
1251 // Chrome for the gradient code.
1252 float mediaDuration = mediaElement->duration();
1253 RefPtr<TimeRanges> timeRanges = mediaElement->buffered();
1254 IntRect trackRect = rect;
1255 int totalWidth = trackRect.width();
1257 trackRect.inflate(-style->borderLeftWidth());
1259 context->setStrokeStyle(NoStroke);
1261 for (unsigned index = 0; index < timeRanges->length(); ++index) {
1262 ExceptionCode ignoredException;
1263 float start = timeRanges->start(index, ignoredException);
1264 float end = timeRanges->end(index, ignoredException);
1265 int width = ((end - start) * totalWidth) / mediaDuration;
1268 rangeRect = trackRect;
1269 rangeRect.setWidth(width);
1271 rangeRect.setLocation(IntPoint(trackRect.x() + start / mediaDuration* totalWidth, trackRect.y()));
1272 rangeRect.setSize(IntSize(width, trackRect.height()));
1275 // Don't bother drawing empty range.
1276 if (rangeRect.isEmpty())
1279 IntPoint sliderTopLeft = rangeRect.location();
1280 IntPoint sliderTopRight = sliderTopLeft;
1281 sliderTopRight.move(0, rangeRect.height());
1283 context->fillRect(FloatRect(rect), m_mediaPanelColor, ColorSpaceDeviceRGB);
1289 bool RenderThemeEfl::paintMediaSliderThumb(RenderObject* object, const PaintInfo& info, const IntRect& rect)
1291 IntSize thumbRect(3, 3);
1292 info.context->fillRoundedRect(rect, thumbRect, thumbRect, thumbRect, thumbRect, m_sliderThumbColor, ColorSpaceDeviceRGB);
1296 bool RenderThemeEfl::paintMediaVolumeSliderContainer(RenderObject*, const PaintInfo& info, const IntRect& rect)
1302 bool RenderThemeEfl::paintMediaVolumeSliderTrack(RenderObject* object, const PaintInfo& info, const IntRect& rect)
1308 bool RenderThemeEfl::paintMediaVolumeSliderThumb(RenderObject* object, const PaintInfo& info, const IntRect& rect)
1314 bool RenderThemeEfl::paintMediaCurrentTime(RenderObject* object, const PaintInfo& info, const IntRect& rect)
1316 info.context->fillRect(FloatRect(rect), m_mediaPanelColor, ColorSpaceDeviceRGB);