1/*
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.
9 *
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.
14 *
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.
19 *
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.
24 *
25 */
26
27#include "config.h"
28#include "RenderThemeEfl.h"
29
30#include "CSSValueKeywords.h"
31#include "CairoUtilitiesEfl.h"
32#include "ExceptionCodePlaceholder.h"
33#include "FontDescription.h"
34#include "GraphicsContext.h"
35#include "HTMLInputElement.h"
36#include "InputTypeNames.h"
37#include "NotImplemented.h"
38#include "Page.h"
39#include "PaintInfo.h"
40#include "PlatformContextCairo.h"
41#include "RenderBox.h"
42#include "RenderObject.h"
43#include "RenderProgress.h"
44#include "RenderSlider.h"
45#include "UserAgentStyleSheets.h"
46
47#include <Ecore_Evas.h>
48#include <Edje.h>
49#include <new>
50#include <wtf/text/CString.h>
51#include <wtf/text/WTFString.h>
52
53#if ENABLE(VIDEO)
54#include "HTMLMediaElement.h"
55#include "HTMLNames.h"
56#include "TimeRanges.h"
57#endif
58
59namespace WebCore {
60#if ENABLE(VIDEO)
61using namespace HTMLNames;
62#endif
63
64// TODO: change from object count to ecore_evas size (bytes)
65// TODO: as objects are webpage/user defined and they can be very large.
66#define RENDER_THEME_EFL_PART_CACHE_MAX 32
67
68// Initialize default font size.
69float RenderThemeEfl::defaultFontSize = 16.0f;
70
71static const float minCancelButtonSize = 5;
72static const float maxCancelButtonSize = 21;
73
74static const float minSearchDecorationButtonSize = 1;
75static const float maxSearchDecorationButtonSize = 15;
76static const float searchFieldDecorationButtonOffset = 3;
77
78// Constants for progress tag animation.
79// These values have been copied from RenderThemeGtk.cpp
80static const int progressAnimationFrames = 10;
81static const double progressAnimationInterval = 0.125;
82
83static const int sliderThumbWidth = 29;
84static const int sliderThumbHeight = 11;
85#if ENABLE(VIDEO)
86static const int mediaSliderHeight = 14;
87static const int mediaSliderThumbWidth = 12;
88static const int mediaSliderThumbHeight = 12;
89#endif
90
91#define _ASSERT_ON_RELEASE_RETURN(o, fmt, ...) \
92    do { if (!o) { EINA_LOG_CRIT(fmt, ## __VA_ARGS__); ASSERT(o); return; } } while (0)
93#define _ASSERT_ON_RELEASE_RETURN_VAL(o, val, fmt, ...) \
94    do { if (!o) { EINA_LOG_CRIT(fmt, ## __VA_ARGS__); ASSERT(o); return val; } } while (0)
95
96
97static const char* toEdjeGroup(FormType type)
98{
99    static const char* groups[] = {
100#define W(n) "webkit/widget/"n
101        W("button"),
102        W("radio"),
103        W("entry"),
104        W("checkbox"),
105        W("combo"),
106#if ENABLE(PROGRESS_ELEMENT)
107        W("progressbar"),
108#endif
109        W("search/field"),
110        W("search/decoration"),
111        W("search/results_button"),
112        W("search/results_decoration"),
113        W("search/cancel_button"),
114        W("slider/vertical"),
115        W("slider/horizontal"),
116        W("slider/thumb_vertical"),
117        W("slider/thumb_horizontal"),
118#if ENABLE(VIDEO)
119        W("mediacontrol/playpause_button"),
120        W("mediacontrol/mute_button"),
121        W("mediacontrol/seekforward_button"),
122        W("mediacontrol/seekbackward_button"),
123        W("mediacontrol/fullscreen_button"),
124#endif
125#if ENABLE(VIDEO_TRACK)
126        W("mediacontrol/toggle_captions_button"),
127#endif
128        W("spinner"),
129#undef W
130        0
131    };
132    ASSERT(type >= 0);
133    ASSERT((size_t)type < sizeof(groups) / sizeof(groups[0])); // Out of sync?
134    return groups[type];
135}
136
137static bool setSourceGroupForEdjeObject(Evas_Object* o, const String& themePath, const char* group)
138{
139    ASSERT(o);
140    ASSERT(!themePath.isEmpty());
141
142    if (!edje_object_file_set(o, themePath.utf8().data(), group)) {
143        const char* message = edje_load_error_str(edje_object_load_error_get(o));
144        EINA_LOG_ERR("Could not set theme group '%s' of file '%s': %s", group, themePath.utf8().data(), message);
145        return false;
146    }
147
148    return true;
149}
150
151void RenderThemeEfl::adjustSizeConstraints(RenderStyle* style, FormType type) const
152{
153    loadThemeIfNeeded();
154
155    // These are always valid, even if no theme could be loaded.
156    const ThemePartDesc* desc = m_partDescs + (size_t)type;
157
158    if (style->minWidth().isIntrinsic())
159        style->setMinWidth(desc->min.width());
160    if (style->minHeight().isIntrinsic())
161        style->setMinHeight(desc->min.height());
162
163    if (desc->max.width().value() > 0 && style->maxWidth().isIntrinsicOrAuto())
164        style->setMaxWidth(desc->max.width());
165    if (desc->max.height().value() > 0 && style->maxHeight().isIntrinsicOrAuto())
166        style->setMaxHeight(desc->max.height());
167
168    style->setPaddingTop(desc->padding.top());
169    style->setPaddingBottom(desc->padding.bottom());
170    style->setPaddingLeft(desc->padding.left());
171    style->setPaddingRight(desc->padding.right());
172}
173
174static bool isFormElementTooLargeToDisplay(const IntSize& elementSize)
175{
176    // This limit of 20000 pixels is hardcoded inside edje -- anything above this size
177    // will be clipped. This value seems to be reasonable enough so that hardcoding it
178    // here won't be a problem.
179    static const int maxEdjeDimension = 20000;
180
181    return elementSize.width() > maxEdjeDimension || elementSize.height() > maxEdjeDimension;
182}
183
184PassOwnPtr<RenderThemeEfl::ThemePartCacheEntry> RenderThemeEfl::ThemePartCacheEntry::create(const String& themePath, FormType type, const IntSize& size)
185{
186    ASSERT(!themePath.isEmpty());
187
188    if (isFormElementTooLargeToDisplay(size) || size.isEmpty()) {
189        EINA_LOG_ERR("Cannot render an element of size %dx%d.", size.width(), size.height());
190        return nullptr;
191    }
192
193    OwnPtr<ThemePartCacheEntry> entry = adoptPtr(new ThemePartCacheEntry);
194
195    entry->m_canvas = adoptPtr(ecore_evas_buffer_new(size.width(), size.height()));
196    if (!entry->canvas()) {
197        EINA_LOG_ERR("ecore_evas_buffer_new(%d, %d) failed.", size.width(), size.height());
198        return nullptr;
199    }
200
201    // By default EFL creates buffers without alpha.
202    ecore_evas_alpha_set(entry->canvas(), EINA_TRUE);
203
204    entry->m_edje = adoptRef(edje_object_add(ecore_evas_get(entry->canvas())));
205    ASSERT(entry->edje());
206
207    if (!setSourceGroupForEdjeObject(entry->edje(), themePath, toEdjeGroup(type)))
208        return nullptr;
209
210    entry->m_surface = createSurfaceForBackingStore(entry->canvas());
211    if (!entry->surface())
212        return nullptr;
213
214    evas_object_resize(entry->edje(), size.width(), size.height());
215    evas_object_show(entry->edje());
216
217    entry->type = type;
218    entry->size = size;
219
220    return entry.release();
221}
222
223void RenderThemeEfl::ThemePartCacheEntry::reuse(const String& themePath, FormType newType, const IntSize& newSize)
224{
225    ASSERT(!themePath.isEmpty());
226
227    if (type != newType) {
228        type = newType;
229        if (!setSourceGroupForEdjeObject(edje(), themePath, toEdjeGroup(newType))) {
230            type = FormTypeLast; // Invalidate.
231            return;
232        }
233    }
234
235    if (size != newSize) {
236        size = newSize;
237        ecore_evas_resize(canvas(), newSize.width(), newSize.height());
238        evas_object_resize(edje(), newSize.width(), newSize.height());
239
240        m_surface = createSurfaceForBackingStore(canvas());
241        if (!surface()) {
242            type = FormTypeLast; // Invalidate;
243            return;
244        }
245    }
246}
247
248RenderThemeEfl::ThemePartCacheEntry* RenderThemeEfl::getThemePartFromCache(FormType type, const IntSize& size)
249{
250    void* data;
251    Eina_List* node;
252    Eina_List* reusableNode = 0;
253
254    // Look for the item in the cache.
255    EINA_LIST_FOREACH(m_partCache, node, data) {
256        ThemePartCacheEntry* cachedEntry = static_cast<ThemePartCacheEntry*>(data);
257        if (cachedEntry->size == size) {
258            if (cachedEntry->type == type) {
259                // Found the right item, move it to the head of the list
260                // and return it.
261                m_partCache = eina_list_promote_list(m_partCache, node);
262                return cachedEntry;
263            }
264            // We reuse in priority the last item in the list that has
265            // the requested size.
266            reusableNode = node;
267        }
268    }
269
270    if (eina_list_count(m_partCache) < RENDER_THEME_EFL_PART_CACHE_MAX) {
271        ThemePartCacheEntry* entry = ThemePartCacheEntry::create(themePath(), type, size).leakPtr();
272        if (entry)
273            m_partCache = eina_list_prepend(m_partCache, entry);
274
275        return entry;
276    }
277
278    // The cache is full, reuse the last item we found that had the
279    // requested size to avoid resizing. If there was none, reuse
280    // the last item of the list.
281    if (!reusableNode)
282        reusableNode = eina_list_last(m_partCache);
283
284    ThemePartCacheEntry* reusedEntry = static_cast<ThemePartCacheEntry*>(eina_list_data_get(reusableNode));
285    ASSERT(reusedEntry);
286    reusedEntry->reuse(themePath(), type, size);
287    m_partCache = eina_list_promote_list(m_partCache, reusableNode);
288
289    return reusedEntry;
290}
291
292void RenderThemeEfl::clearThemePartCache()
293{
294    void* data;
295    EINA_LIST_FREE(m_partCache, data)
296        delete static_cast<ThemePartCacheEntry*>(data);
297
298}
299
300void RenderThemeEfl::applyEdjeStateFromForm(Evas_Object* object, ControlStates states)
301{
302    const char *signals[] = { // keep in sync with WebCore/platform/ThemeTypes.h
303        "hovered",
304        "pressed",
305        "focused",
306        "enabled",
307        "checked",
308        "read-only",
309        "default",
310        "window-inactive",
311        "indeterminate",
312        "spinup"
313    };
314
315    edje_object_signal_emit(object, "reset", "");
316
317    for (size_t i = 0; i < WTF_ARRAY_LENGTH(signals); ++i) {
318        if (states & (1 << i))
319            edje_object_signal_emit(object, signals[i], "");
320    }
321}
322
323void RenderThemeEfl::applyEdjeRTLState(Evas_Object* edje, RenderObject* object, FormType type, const IntRect& rect)
324{
325    if (type == SliderVertical || type == SliderHorizontal) {
326        if (!object->isSlider())
327            return; // probably have -webkit-appearance: slider..
328
329        RenderSlider* renderSlider = toRenderSlider(object);
330        HTMLInputElement* input = renderSlider->node()->toInputElement();
331        double valueRange = input->maximum() - input->minimum();
332
333        OwnPtr<Edje_Message_Float_Set> msg = adoptPtr(static_cast<Edje_Message_Float_Set*>(::operator new (sizeof(Edje_Message_Float_Set) + sizeof(double))));
334        msg->count = 2;
335
336        // The first parameter of the message decides if the progress bar
337        // grows from the end of the slider or from the beginning. On vertical
338        // sliders, it should always be the same and will not be affected by
339        // text direction settings.
340        if (object->style()->direction() == RTL || type == SliderVertical)
341            msg->val[0] = 1;
342        else
343            msg->val[0] = 0;
344
345        msg->val[1] = (input->valueAsNumber() - input->minimum()) / valueRange;
346        edje_object_message_send(edje, EDJE_MESSAGE_FLOAT_SET, 0, msg.get());
347#if ENABLE(PROGRESS_ELEMENT)
348    } else if (type == ProgressBar) {
349        RenderProgress* renderProgress = toRenderProgress(object);
350
351        int max = rect.width();
352        double value = renderProgress->position();
353
354        OwnPtr<Edje_Message_Float_Set> msg = adoptPtr(static_cast<Edje_Message_Float_Set*>(::operator new (sizeof(Edje_Message_Float_Set) + sizeof(double))));
355        msg->count = 2;
356
357        if (object->style()->direction() == RTL)
358            msg->val[0] = (1.0 - value) * max;
359        else
360            msg->val[0] = 0;
361        msg->val[1] = value;
362        edje_object_message_send(edje, EDJE_MESSAGE_FLOAT_SET, 0, msg.get());
363#else
364        UNUSED_PARAM(rect);
365#endif
366    }
367}
368
369bool RenderThemeEfl::paintThemePart(RenderObject* object, FormType type, const PaintInfo& info, const IntRect& rect)
370{
371    loadThemeIfNeeded();
372    _ASSERT_ON_RELEASE_RETURN_VAL(edje(), false, "Could not paint native HTML part due to missing theme.");
373
374    ThemePartCacheEntry* entry = getThemePartFromCache(type, rect.size());
375    if (!entry)
376        return false;
377
378    applyEdjeStateFromForm(entry->edje(), controlStatesForRenderer(object));
379    applyEdjeRTLState(entry->edje(), object, type, rect);
380
381    edje_object_calc_force(entry->edje());
382    edje_object_message_signal_process(entry->edje());
383    evas_render(ecore_evas_get(entry->canvas()));
384
385    cairo_t* cairo = info.context->platformContext()->cr();
386    ASSERT(cairo);
387
388    cairo_save(cairo);
389    cairo_set_source_surface(cairo, entry->surface(), rect.x(), rect.y());
390    cairo_paint_with_alpha(cairo, 1.0);
391    cairo_restore(cairo);
392
393    return false;
394}
395
396PassRefPtr<RenderTheme> RenderThemeEfl::create(Page* page)
397{
398    return adoptRef(new RenderThemeEfl(page));
399}
400
401PassRefPtr<RenderTheme> RenderTheme::themeForPage(Page* page)
402{
403    if (page)
404        return RenderThemeEfl::create(page);
405
406    static RenderTheme* fallback = RenderThemeEfl::create(0).leakRef();
407    return fallback;
408}
409
410static void applyColorCallback(void* data, Evas_Object*, const char* /* signal */, const char* colorClass)
411{
412    RenderThemeEfl* that = static_cast<RenderThemeEfl*>(data);
413    that->setColorFromThemeClass(colorClass);
414    that->platformColorsDidChange(); // Triggers relayout.
415}
416
417static bool fillColorsFromEdjeClass(Evas_Object* o, const char* colorClass, Color* color1, Color* color2 = 0, Color* color3 = 0)
418{
419    int r1, g1, b1, a1;
420    int r2, g2, b2, a2;
421    int r3, g3, b3, a3;
422
423    if (!edje_object_color_class_get(o, colorClass, &r1, &g1, &b1, &a1, &r2, &g2, &b2, &a2, &r3, &g3, &b3, &a3))
424        return false;
425
426    if (color1)
427        color1->setRGB(makeRGBA(r1, g1, b1, a1));
428    if (color2)
429        color2->setRGB(makeRGBA(r2, g2, b2, a2));
430    if (color3)
431        color3->setRGB(makeRGBA(r3, g3, b3, a3));
432
433    return true;
434}
435
436void RenderThemeEfl::setColorFromThemeClass(const char* colorClass)
437{
438    ASSERT(edje());
439
440    if (!strcmp("webkit/selection/foreground", colorClass))
441        m_supportsSelectionForegroundColor = fillColorsFromEdjeClass(edje(), colorClass, &m_activeSelectionForegroundColor, &m_inactiveSelectionForegroundColor);
442    else if (!strcmp("webkit/selection/background", colorClass))
443        fillColorsFromEdjeClass(edje(), colorClass, &m_activeSelectionBackgroundColor, &m_inactiveSelectionBackgroundColor);
444    else if (!strcmp("webkit/focus_ring", colorClass)) {
445        if (!fillColorsFromEdjeClass(edje(), colorClass, &m_focusRingColor))
446            return;
447
448        // platformFocusRingColor() is only used for the default theme (without page)
449        // The following is ugly, but no other way to do it unless we change it to use page themes as much as possible.
450        RenderTheme::setCustomFocusRingColor(m_focusRingColor);
451    }
452}
453
454void RenderThemeEfl::setThemePath(const String& newThemePath)
455{
456    if (newThemePath == m_themePath)
457        return;
458
459    if (newThemePath.isEmpty()) {
460        EINA_LOG_CRIT("No valid theme defined, things will not work properly.");
461        return;
462    }
463
464    String oldThemePath = m_themePath;
465    m_themePath = newThemePath;
466
467    // Keep the consistence by restoring the previous theme path
468    // if we cannot load the new one.
469    if (!loadTheme())
470        m_themePath = oldThemePath;
471}
472
473String RenderThemeEfl::themePath() const
474{
475#ifndef NDEBUG
476    if (edje()) {
477        const char* path;
478        edje_object_file_get(edje(), &path, 0);
479        ASSERT(m_themePath == path);
480    }
481#endif
482    return m_themePath;
483}
484
485bool RenderThemeEfl::loadTheme()
486{
487    ASSERT(!m_themePath.isEmpty());
488
489    if (!canvas()) {
490        m_canvas = adoptPtr(ecore_evas_buffer_new(1, 1));
491        _ASSERT_ON_RELEASE_RETURN_VAL(canvas(), false,
492                "Could not create canvas required by theme, things will not work properly.");
493    }
494
495    RefPtr<Evas_Object> o = adoptRef(edje_object_add(ecore_evas_get(canvas())));
496    _ASSERT_ON_RELEASE_RETURN_VAL(o, false, "Could not create new base Edje object.");
497
498    if (!setSourceGroupForEdjeObject(o.get(), m_themePath, "webkit/base"))
499        return false; // Keep current theme.
500
501    // Invalidate existing theme part cache.
502    if (edje())
503        clearThemePartCache();
504
505    // Set new loaded theme, and apply it.
506    m_edje = o;
507
508    edje_object_signal_callback_add(edje(), "color_class,set", "webkit/selection/foreground", applyColorCallback, this);
509    edje_object_signal_callback_add(edje(), "color_class,set", "webkit/selection/background", applyColorCallback, this);
510    edje_object_signal_callback_add(edje(), "color_class,set", "webkit/focus_ring", applyColorCallback, this);
511
512    applyPartDescriptionsFrom(m_themePath);
513
514    setColorFromThemeClass("webkit/selection/foreground");
515    setColorFromThemeClass("webkit/selection/background");
516    setColorFromThemeClass("webkit/focus_ring");
517
518    platformColorsDidChange(); // Schedules a relayout, do last.
519
520    return true;
521}
522
523void RenderThemeEfl::applyPartDescriptionFallback(ThemePartDesc* desc)
524{
525    desc->min.setWidth(Length(0, Fixed));
526    desc->min.setHeight(Length(0, Fixed));
527
528    desc->max.setWidth(Length(0, Fixed));
529    desc->max.setHeight(Length(0, Fixed));
530
531    desc->padding = LengthBox(0, 0, 0, 0);
532}
533
534void RenderThemeEfl::applyPartDescription(Evas_Object* object, ThemePartDesc* desc)
535{
536    Evas_Coord minw, minh, maxw, maxh;
537
538    edje_object_size_min_get(object, &minw, &minh);
539    if (!minw && !minh)
540        edje_object_size_min_calc(object, &minw, &minh);
541
542    desc->min.setWidth(Length(minw, Fixed));
543    desc->min.setHeight(Length(minh, Fixed));
544
545    edje_object_size_max_get(object, &maxw, &maxh);
546    desc->max.setWidth(Length(maxw, Fixed));
547    desc->max.setHeight(Length(maxh, Fixed));
548
549    if (!edje_object_part_exists(object, "text_confinement"))
550        desc->padding = LengthBox(0, 0, 0, 0);
551    else {
552        Evas_Coord px, py, pw, ph;
553        Evas_Coord ox = 0, oy = 0, ow = 0, oh = 0;
554        int t, r, b, l;
555
556        if (minw > 0)
557            ow = minw;
558        else
559            ow = 100;
560        if (minh > 0)
561            oh = minh;
562        else
563            oh = 100;
564        if (maxw > 0 && ow > maxw)
565            ow = maxw;
566        if (maxh > 0 && oh > maxh)
567            oh = maxh;
568
569        evas_object_move(object, ox, oy);
570        evas_object_resize(object, ow, oh);
571        edje_object_calc_force(object);
572        edje_object_message_signal_process(object);
573        edje_object_part_geometry_get(object, "text_confinement", &px, &py, &pw, &ph);
574
575        t = py - oy;
576        b = (oh + oy) - (ph + py);
577
578        l = px - ox;
579        r = (ow + ox) - (pw + px);
580
581        desc->padding = LengthBox(t, r, b, l);
582    }
583}
584
585void RenderThemeEfl::applyPartDescriptionsFrom(const String& themePath)
586{
587    RefPtr<Evas_Object> temp = adoptRef(edje_object_add(ecore_evas_get(canvas())));
588    _ASSERT_ON_RELEASE_RETURN(temp, "Could not create Edje object.");
589
590    for (size_t i = 0; i < FormTypeLast; i++) {
591        FormType type = static_cast<FormType>(i);
592        m_partDescs[i].type = type;
593        if (!setSourceGroupForEdjeObject(temp.get(), themePath, toEdjeGroup(type)))
594            applyPartDescriptionFallback(m_partDescs + i);
595        else
596            applyPartDescription(temp.get(), m_partDescs + i);
597    }
598}
599
600RenderThemeEfl::RenderThemeEfl(Page* page)
601    : RenderTheme()
602    , m_page(page)
603    , m_activeSelectionBackgroundColor(0, 0, 255)
604    , m_activeSelectionForegroundColor(Color::white)
605    , m_inactiveSelectionBackgroundColor(0, 0, 128)
606    , m_inactiveSelectionForegroundColor(200, 200, 200)
607    , m_focusRingColor(32, 32, 224, 224)
608    , m_sliderThumbColor(Color::darkGray)
609#if ENABLE(VIDEO)
610    , m_mediaPanelColor(220, 220, 195) // light tannish color.
611    , m_mediaSliderColor(Color::white)
612#endif
613    , m_supportsSelectionForegroundColor(false)
614    , m_partCache(0)
615{
616}
617
618RenderThemeEfl::~RenderThemeEfl()
619{
620    clearThemePartCache();
621}
622
623static bool supportsFocus(ControlPart appearance)
624{
625    switch (appearance) {
626    case PushButtonPart:
627    case ButtonPart:
628    case TextFieldPart:
629    case TextAreaPart:
630    case SearchFieldPart:
631    case MenulistPart:
632    case RadioPart:
633    case CheckboxPart:
634    case SliderVerticalPart:
635    case SliderHorizontalPart:
636        return true;
637    default:
638        return false;
639    }
640}
641
642bool RenderThemeEfl::supportsFocusRing(const RenderStyle* style) const
643{
644    return supportsFocus(style->appearance());
645}
646
647bool RenderThemeEfl::controlSupportsTints(const RenderObject* object) const
648{
649    return isEnabled(object);
650}
651
652int RenderThemeEfl::baselinePosition(const RenderObject* object) const
653{
654    if (!object->isBox())
655        return 0;
656
657    if (object->style()->appearance() == CheckboxPart
658    ||  object->style()->appearance() == RadioPart)
659        return toRenderBox(object)->marginTop() + toRenderBox(object)->height() - 3;
660
661    return RenderTheme::baselinePosition(object);
662}
663
664Color RenderThemeEfl::platformActiveSelectionBackgroundColor() const
665{
666    loadThemeIfNeeded();
667    return m_activeSelectionBackgroundColor;
668}
669
670Color RenderThemeEfl::platformInactiveSelectionBackgroundColor() const
671{
672    loadThemeIfNeeded();
673    return m_inactiveSelectionBackgroundColor;
674}
675
676Color RenderThemeEfl::platformActiveSelectionForegroundColor() const
677{
678    loadThemeIfNeeded();
679    return m_activeSelectionForegroundColor;
680}
681
682Color RenderThemeEfl::platformInactiveSelectionForegroundColor() const
683{
684    loadThemeIfNeeded();
685    return m_inactiveSelectionForegroundColor;
686}
687
688Color RenderThemeEfl::platformFocusRingColor() const
689{
690    loadThemeIfNeeded();
691    return m_focusRingColor;
692}
693
694bool RenderThemeEfl::supportsSelectionForegroundColors() const
695{
696    loadThemeIfNeeded();
697    return m_supportsSelectionForegroundColor;
698}
699
700bool RenderThemeEfl::paintSliderTrack(RenderObject* object, const PaintInfo& info, const IntRect& rect)
701{
702    if (object->style()->appearance() == SliderHorizontalPart)
703        paintThemePart(object, SliderHorizontal, info, rect);
704    else
705        paintThemePart(object, SliderVertical, info, rect);
706
707#if ENABLE(DATALIST_ELEMENT)
708    paintSliderTicks(object, info, rect);
709#endif
710
711    return false;
712}
713
714void RenderThemeEfl::adjustSliderTrackStyle(StyleResolver*, RenderStyle* style, Element*) const
715{
716    style->setBoxShadow(nullptr);
717}
718
719void RenderThemeEfl::adjustSliderThumbStyle(StyleResolver* styleResolver, RenderStyle* style, Element* element) const
720{
721    RenderTheme::adjustSliderThumbStyle(styleResolver, style, element);
722    style->setBoxShadow(nullptr);
723}
724
725void RenderThemeEfl::adjustSliderThumbSize(RenderStyle* style, Element*) const
726{
727    ControlPart part = style->appearance();
728    if (part == SliderThumbVerticalPart) {
729        style->setWidth(Length(sliderThumbHeight, Fixed));
730        style->setHeight(Length(sliderThumbWidth, Fixed));
731    } else if (part == SliderThumbHorizontalPart) {
732        style->setWidth(Length(sliderThumbWidth, Fixed));
733        style->setHeight(Length(sliderThumbHeight, Fixed));
734#if ENABLE(VIDEO)
735    } else if (part == MediaSliderThumbPart) {
736        style->setWidth(Length(mediaSliderThumbWidth, Fixed));
737        style->setHeight(Length(mediaSliderThumbHeight, Fixed));
738#endif
739    }
740}
741
742#if ENABLE(DATALIST_ELEMENT)
743IntSize RenderThemeEfl::sliderTickSize() const
744{
745    return IntSize(1, 6);
746}
747
748int RenderThemeEfl::sliderTickOffsetFromTrackCenter() const
749{
750    static const int sliderTickOffset = -12;
751
752    return sliderTickOffset;
753}
754
755LayoutUnit RenderThemeEfl::sliderTickSnappingThreshold() const
756{
757    // The same threshold value as the Chromium port.
758    return 5;
759}
760#endif
761
762bool RenderThemeEfl::supportsDataListUI(const AtomicString& type) const
763{
764#if ENABLE(DATALIST_ELEMENT)
765    // FIXME: We need to support other types.
766    return type == InputTypeNames::email()
767        || type == InputTypeNames::range()
768        || type == InputTypeNames::search()
769        || type == InputTypeNames::url();
770#else
771    UNUSED_PARAM(type);
772    return false;
773#endif
774}
775
776bool RenderThemeEfl::paintSliderThumb(RenderObject* object, const PaintInfo& info, const IntRect& rect)
777{
778    if (object->style()->appearance() == SliderThumbHorizontalPart)
779        paintThemePart(object, SliderThumbHorizontal, info, rect);
780    else
781        paintThemePart(object, SliderThumbVertical, info, rect);
782
783    return false;
784}
785
786void RenderThemeEfl::adjustCheckboxStyle(StyleResolver* styleResolver, RenderStyle* style, Element* element) const
787{
788    if (!m_page && element && element->document()->page()) {
789        static_cast<RenderThemeEfl*>(element->document()->page()->theme())->adjustCheckboxStyle(styleResolver, style, element);
790        return;
791    }
792
793    adjustSizeConstraints(style, CheckBox);
794
795    style->resetBorder();
796
797    const ThemePartDesc* desc = m_partDescs + (size_t)CheckBox;
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());
802}
803
804bool RenderThemeEfl::paintCheckbox(RenderObject* object, const PaintInfo& info, const IntRect& rect)
805{
806    return paintThemePart(object, CheckBox, info, rect);
807}
808
809void RenderThemeEfl::adjustRadioStyle(StyleResolver* styleResolver, RenderStyle* style, Element* element) const
810{
811    if (!m_page && element && element->document()->page()) {
812        static_cast<RenderThemeEfl*>(element->document()->page()->theme())->adjustRadioStyle(styleResolver, style, element);
813        return;
814    }
815
816    adjustSizeConstraints(style, RadioButton);
817
818    style->resetBorder();
819
820    const ThemePartDesc* desc = m_partDescs + (size_t)RadioButton;
821    if (style->width().value() < desc->min.width().value())
822        style->setWidth(desc->min.width());
823    if (style->height().value() < desc->min.height().value())
824        style->setHeight(desc->min.height());
825}
826
827bool RenderThemeEfl::paintRadio(RenderObject* object, const PaintInfo& info, const IntRect& rect)
828{
829    return paintThemePart(object, RadioButton, info, rect);
830}
831
832void RenderThemeEfl::adjustButtonStyle(StyleResolver* styleResolver, RenderStyle* style, Element* element) const
833{
834    if (!m_page && element && element->document()->page()) {
835        static_cast<RenderThemeEfl*>(element->document()->page()->theme())->adjustButtonStyle(styleResolver, style, element);
836        return;
837    }
838
839    // adjustSizeConstrains can make SquareButtonPart's size wrong (by adjusting paddings), so call it only for PushButtonPart and ButtonPart
840    if (style->appearance() == PushButtonPart || style->appearance() == ButtonPart)
841        adjustSizeConstraints(style, Button);
842}
843
844bool RenderThemeEfl::paintButton(RenderObject* object, const PaintInfo& info, const IntRect& rect)
845{
846    return paintThemePart(object, Button, info, rect);
847}
848
849void RenderThemeEfl::adjustMenuListStyle(StyleResolver* styleResolver, RenderStyle* style, Element* element) const
850{
851    if (!m_page && element && element->document()->page()) {
852        static_cast<RenderThemeEfl*>(element->document()->page()->theme())->adjustMenuListStyle(styleResolver, style, element);
853        return;
854    }
855    adjustSizeConstraints(style, ComboBox);
856    style->resetBorder();
857    style->setWhiteSpace(PRE);
858
859    style->setLineHeight(RenderStyle::initialLineHeight());
860}
861
862bool RenderThemeEfl::paintMenuList(RenderObject* object, const PaintInfo& info, const IntRect& rect)
863{
864    return paintThemePart(object, ComboBox, info, rect);
865}
866
867void RenderThemeEfl::adjustMenuListButtonStyle(StyleResolver* styleResolver, RenderStyle* style, Element* element) const
868{
869    // Height is locked to auto if height is not specified.
870    style->setHeight(Length(Auto));
871
872    // The <select> box must be at least 12px high for the button to render the text inside the box without clipping.
873    const int dropDownBoxMinHeight = 12;
874
875    // Calculate min-height of the <select> element.
876    int minHeight = style->fontMetrics().height();
877    minHeight = max(minHeight, dropDownBoxMinHeight);
878    style->setMinHeight(Length(minHeight, Fixed));
879
880    adjustMenuListStyle(styleResolver, style, element);
881}
882
883bool RenderThemeEfl::paintMenuListButton(RenderObject* object, const PaintInfo& info, const IntRect& rect)
884{
885    return paintMenuList(object, info, rect);
886}
887
888void RenderThemeEfl::adjustTextFieldStyle(StyleResolver* styleResolver, RenderStyle* style, Element* element) const
889{
890    if (!m_page && element && element->document()->page()) {
891        static_cast<RenderThemeEfl*>(element->document()->page()->theme())->adjustTextFieldStyle(styleResolver, style, element);
892        return;
893    }
894    adjustSizeConstraints(style, TextField);
895    style->resetBorder();
896}
897
898bool RenderThemeEfl::paintTextField(RenderObject* object, const PaintInfo& info, const IntRect& rect)
899{
900    return paintThemePart(object, TextField, info, rect);
901}
902
903void RenderThemeEfl::adjustTextAreaStyle(StyleResolver*, RenderStyle*, Element*) const
904{
905}
906
907bool RenderThemeEfl::paintTextArea(RenderObject* object, const PaintInfo& info, const IntRect& rect)
908{
909    return paintTextField(object, info, rect);
910}
911
912void RenderThemeEfl::adjustSearchFieldDecorationStyle(StyleResolver* styleResolver, RenderStyle* style, Element* element) const
913{
914    if (!m_page && element && element->document()->page()) {
915        static_cast<RenderThemeEfl*>(element->document()->page()->theme())->adjustSearchFieldDecorationStyle(styleResolver, style, element);
916        return;
917    }
918    adjustSizeConstraints(style, SearchFieldDecoration);
919    style->resetBorder();
920    style->setWhiteSpace(PRE);
921
922    float fontScale = style->fontSize() / defaultFontSize;
923    int decorationSize = lroundf(std::min(std::max(minSearchDecorationButtonSize, defaultFontSize * fontScale), maxSearchDecorationButtonSize));
924
925    style->setWidth(Length(decorationSize + searchFieldDecorationButtonOffset, Fixed));
926    style->setHeight(Length(decorationSize, Fixed));
927}
928
929bool RenderThemeEfl::paintSearchFieldDecoration(RenderObject* object, const PaintInfo& info, const IntRect& rect)
930{
931    return paintThemePart(object, SearchFieldDecoration, info, rect);
932}
933
934void RenderThemeEfl::adjustSearchFieldResultsButtonStyle(StyleResolver* styleResolver, RenderStyle* style, Element* element) const
935{
936    if (!m_page && element && element->document()->page()) {
937        static_cast<RenderThemeEfl*>(element->document()->page()->theme())->adjustSearchFieldResultsButtonStyle(styleResolver, style, element);
938        return;
939    }
940    adjustSizeConstraints(style, SearchFieldResultsButton);
941    style->resetBorder();
942    style->setWhiteSpace(PRE);
943}
944
945bool RenderThemeEfl::paintSearchFieldResultsButton(RenderObject* object, const PaintInfo& info, const IntRect& rect)
946{
947    return paintThemePart(object, SearchFieldResultsButton, info, rect);
948}
949
950void RenderThemeEfl::adjustSearchFieldResultsDecorationStyle(StyleResolver* styleResolver, RenderStyle* style, Element* element) const
951{
952    if (!m_page && element && element->document()->page()) {
953        static_cast<RenderThemeEfl*>(element->document()->page()->theme())->adjustSearchFieldResultsDecorationStyle(styleResolver, style, element);
954        return;
955    }
956    adjustSizeConstraints(style, SearchFieldResultsDecoration);
957    style->resetBorder();
958    style->setWhiteSpace(PRE);
959}
960
961bool RenderThemeEfl::paintSearchFieldResultsDecoration(RenderObject* object, const PaintInfo& info, const IntRect& rect)
962{
963    return paintThemePart(object, SearchFieldResultsDecoration, info, rect);
964}
965
966void RenderThemeEfl::adjustSearchFieldCancelButtonStyle(StyleResolver* styleResolver, RenderStyle* style, Element* element) const
967{
968    if (!m_page && element && element->document()->page()) {
969        static_cast<RenderThemeEfl*>(element->document()->page()->theme())->adjustSearchFieldCancelButtonStyle(styleResolver, style, element);
970        return;
971    }
972    adjustSizeConstraints(style, SearchFieldCancelButton);
973    style->resetBorder();
974    style->setWhiteSpace(PRE);
975
976    // Logic taken from RenderThemeChromium.cpp.
977    // Scale the button size based on the font size.
978    float fontScale = style->fontSize() / defaultFontSize;
979    int cancelButtonSize = lroundf(std::min(std::max(minCancelButtonSize, defaultFontSize * fontScale), maxCancelButtonSize));
980
981    style->setWidth(Length(cancelButtonSize, Fixed));
982    style->setHeight(Length(cancelButtonSize, Fixed));
983}
984
985bool RenderThemeEfl::paintSearchFieldCancelButton(RenderObject* object, const PaintInfo& info, const IntRect& rect)
986{
987    return paintThemePart(object, SearchFieldCancelButton, info, rect);
988}
989
990void RenderThemeEfl::adjustSearchFieldStyle(StyleResolver* styleResolver, RenderStyle* style, Element* element) const
991{
992    if (!m_page && element && element->document()->page()) {
993        static_cast<RenderThemeEfl*>(element->document()->page()->theme())->adjustSearchFieldStyle(styleResolver, style, element);
994        return;
995    }
996    adjustSizeConstraints(style, SearchField);
997    style->resetBorder();
998    style->setWhiteSpace(PRE);
999}
1000
1001bool RenderThemeEfl::paintSearchField(RenderObject* object, const PaintInfo& info, const IntRect& rect)
1002{
1003    return paintThemePart(object, SearchField, info, rect);
1004}
1005
1006void RenderThemeEfl::adjustInnerSpinButtonStyle(StyleResolver* styleResolver, RenderStyle* style, Element* element) const
1007{
1008    if (!m_page && element && element->document()->page()) {
1009        static_cast<RenderThemeEfl*>(element->document()->page()->theme())->adjustInnerSpinButtonStyle(styleResolver, style, element);
1010        return;
1011    }
1012    adjustSizeConstraints(style, Spinner);
1013}
1014
1015bool RenderThemeEfl::paintInnerSpinButton(RenderObject* object, const PaintInfo& info, const IntRect& rect)
1016{
1017    return paintThemePart(object, Spinner, info, rect);
1018}
1019
1020void RenderThemeEfl::setDefaultFontSize(int size)
1021{
1022    defaultFontSize = size;
1023}
1024
1025void RenderThemeEfl::systemFont(int, FontDescription& fontDescription) const
1026{
1027    // It was called by RenderEmbeddedObject::paintReplaced to render alternative string.
1028    // To avoid cairo_error while rendering, fontDescription should be passed.
1029    DEFINE_STATIC_LOCAL(String, fontFace, (ASCIILiteral("Sans")));
1030    float fontSize = defaultFontSize;
1031
1032    fontDescription.setOneFamily(fontFace);
1033    fontDescription.setSpecifiedSize(fontSize);
1034    fontDescription.setIsAbsoluteSize(true);
1035    fontDescription.setGenericFamily(FontDescription::NoFamily);
1036    fontDescription.setWeight(FontWeightNormal);
1037    fontDescription.setItalic(false);
1038}
1039
1040#if ENABLE(PROGRESS_ELEMENT)
1041void RenderThemeEfl::adjustProgressBarStyle(StyleResolver*, RenderStyle* style, Element*) const
1042{
1043    style->setBoxShadow(nullptr);
1044}
1045
1046double RenderThemeEfl::animationRepeatIntervalForProgressBar(RenderProgress*) const
1047{
1048    return progressAnimationInterval;
1049}
1050
1051double RenderThemeEfl::animationDurationForProgressBar(RenderProgress*) const
1052{
1053    return progressAnimationInterval * progressAnimationFrames * 2; // "2" for back and forth;
1054}
1055
1056bool RenderThemeEfl::paintProgressBar(RenderObject* object, const PaintInfo& info, const IntRect& rect)
1057{
1058    if (!object->isProgress())
1059        return true;
1060
1061    return paintThemePart(object, ProgressBar, info, rect);
1062}
1063#endif
1064
1065#if ENABLE(VIDEO)
1066bool RenderThemeEfl::emitMediaButtonSignal(FormType formType, MediaControlElementType mediaElementType, const IntRect& rect)
1067{
1068    loadThemeIfNeeded();
1069    _ASSERT_ON_RELEASE_RETURN_VAL(edje(), false, "Could not paint native HTML part due to missing theme.");
1070
1071    ThemePartCacheEntry* entry = getThemePartFromCache(formType, rect.size());
1072    _ASSERT_ON_RELEASE_RETURN_VAL(entry, false, "Could not paint native HTML part due to missing theme part.");
1073
1074    if (mediaElementType == MediaPlayButton)
1075        edje_object_signal_emit(entry->edje(), "play", "");
1076    else if (mediaElementType == MediaPauseButton)
1077        edje_object_signal_emit(entry->edje(), "pause", "");
1078    else if (mediaElementType == MediaMuteButton)
1079        edje_object_signal_emit(entry->edje(), "mute", "");
1080    else if (mediaElementType == MediaUnMuteButton)
1081        edje_object_signal_emit(entry->edje(), "sound", "");
1082    else if (mediaElementType == MediaSeekForwardButton)
1083        edje_object_signal_emit(entry->edje(), "seekforward", "");
1084    else if (mediaElementType == MediaSeekBackButton)
1085        edje_object_signal_emit(entry->edje(), "seekbackward", "");
1086    else if (mediaElementType == MediaEnterFullscreenButton)
1087        edje_object_signal_emit(entry->edje(), "fullscreen_enter", "");
1088    else if (mediaElementType == MediaExitFullscreenButton)
1089        edje_object_signal_emit(entry->edje(), "fullscreen_exit", "");
1090#if ENABLE(VIDEO_TRACK)
1091    else if (mediaElementType == MediaShowClosedCaptionsButton)
1092        edje_object_signal_emit(entry->edje(), "show_captions", "");
1093    else if (mediaElementType == MediaHideClosedCaptionsButton)
1094        edje_object_signal_emit(entry->edje(), "hide_captions", "");
1095#endif
1096    else
1097        return false;
1098
1099    return true;
1100}
1101
1102String RenderThemeEfl::extraMediaControlsStyleSheet()
1103{
1104    return String(mediaControlsEflUserAgentStyleSheet, sizeof(mediaControlsEflUserAgentStyleSheet));
1105}
1106
1107#if ENABLE(FULLSCREEN_API)
1108String RenderThemeEfl::extraFullScreenStyleSheet()
1109{
1110    return String(mediaControlsEflFullscreenUserAgentStyleSheet, sizeof(mediaControlsEflFullscreenUserAgentStyleSheet));
1111}
1112#endif
1113
1114String RenderThemeEfl::formatMediaControlsCurrentTime(float currentTime, float duration) const
1115{
1116    return formatMediaControlsTime(currentTime) + " / " + formatMediaControlsTime(duration);
1117}
1118
1119bool RenderThemeEfl::hasOwnDisabledStateHandlingFor(ControlPart part) const
1120{
1121    return (part != MediaMuteButtonPart);
1122}
1123
1124bool RenderThemeEfl::paintMediaFullscreenButton(RenderObject* object, const PaintInfo& info, const IntRect& rect)
1125{
1126    Node* mediaNode = object->node() ? object->node()->shadowHost() : 0;
1127    if (!mediaNode)
1128        mediaNode = object->node();
1129    if (!mediaNode || !mediaNode->isElementNode() || !toElement(mediaNode)->isMediaElement())
1130        return false;
1131
1132    HTMLMediaElement* mediaElement = static_cast<HTMLMediaElement*>(mediaNode);
1133    if (!emitMediaButtonSignal(FullScreenButton, mediaElement->isFullscreen() ? MediaExitFullscreenButton : MediaEnterFullscreenButton, rect))
1134        return false;
1135
1136    return paintThemePart(object, FullScreenButton, info, rect);
1137}
1138
1139bool RenderThemeEfl::paintMediaMuteButton(RenderObject* object, const PaintInfo& info, const IntRect& rect)
1140{
1141    Node* mediaNode = object->node() ? object->node()->shadowHost() : 0;
1142    if (!mediaNode)
1143        mediaNode = object->node();
1144    if (!mediaNode || !mediaNode->isElementNode() || !toElement(mediaNode)->isMediaElement())
1145        return false;
1146
1147    HTMLMediaElement* mediaElement = static_cast<HTMLMediaElement*>(mediaNode);
1148
1149    if (!emitMediaButtonSignal(MuteUnMuteButton, mediaElement->muted() ? MediaMuteButton : MediaUnMuteButton, rect))
1150        return false;
1151
1152    return paintThemePart(object, MuteUnMuteButton, info, rect);
1153}
1154
1155bool RenderThemeEfl::paintMediaPlayButton(RenderObject* object, const PaintInfo& info, const IntRect& rect)
1156{
1157    Node* node = object->node();
1158    if (!node || !node->isMediaControlElement())
1159        return false;
1160
1161    if (!emitMediaButtonSignal(PlayPauseButton, mediaControlElementType(node), rect))
1162        return false;
1163
1164    return paintThemePart(object, PlayPauseButton, info, rect);
1165}
1166
1167bool RenderThemeEfl::paintMediaSeekBackButton(RenderObject* object, const PaintInfo& info, const IntRect& rect)
1168{
1169    Node* node = object->node();
1170    if (!node || !node->isMediaControlElement())
1171        return 0;
1172
1173    if (!emitMediaButtonSignal(SeekBackwardButton, mediaControlElementType(node), rect))
1174        return false;
1175
1176    return paintThemePart(object, SeekBackwardButton, info, rect);
1177}
1178
1179bool RenderThemeEfl::paintMediaSeekForwardButton(RenderObject* object, const PaintInfo& info, const IntRect& rect)
1180{
1181    Node* node = object->node();
1182    if (!node || !node->isMediaControlElement())
1183        return 0;
1184
1185    if (!emitMediaButtonSignal(SeekForwardButton, mediaControlElementType(node), rect))
1186        return false;
1187
1188    return paintThemePart(object, SeekForwardButton, info, rect);
1189}
1190
1191bool RenderThemeEfl::paintMediaSliderTrack(RenderObject* object, const PaintInfo& info, const IntRect& rect)
1192{
1193    GraphicsContext* context = info.context;
1194
1195    context->fillRect(FloatRect(rect), m_mediaPanelColor, ColorSpaceDeviceRGB);
1196    context->fillRect(FloatRect(IntRect(rect.x(), rect.y() + (rect.height() - mediaSliderHeight) / 2,
1197                                        rect.width(), mediaSliderHeight)), m_mediaSliderColor, ColorSpaceDeviceRGB);
1198
1199    RenderStyle* style = object->style();
1200    HTMLMediaElement* mediaElement = toParentMediaElement(object);
1201
1202    if (!mediaElement)
1203        return false;
1204
1205    // Draw the buffered ranges. This code is highly inspired from
1206    // Chrome for the gradient code.
1207    float mediaDuration = mediaElement->duration();
1208    RefPtr<TimeRanges> timeRanges = mediaElement->buffered();
1209    IntRect trackRect = rect;
1210    int totalWidth = trackRect.width();
1211
1212    trackRect.inflate(-style->borderLeftWidth());
1213    context->save();
1214    context->setStrokeStyle(NoStroke);
1215
1216    for (unsigned index = 0; index < timeRanges->length(); ++index) {
1217        float start = timeRanges->start(index, IGNORE_EXCEPTION);
1218        float end = timeRanges->end(index, IGNORE_EXCEPTION);
1219        int width = ((end - start) * totalWidth) / mediaDuration;
1220        IntRect rangeRect;
1221        if (!index) {
1222            rangeRect = trackRect;
1223            rangeRect.setWidth(width);
1224        } else {
1225            rangeRect.setLocation(IntPoint(trackRect.x() + start / mediaDuration* totalWidth, trackRect.y()));
1226            rangeRect.setSize(IntSize(width, trackRect.height()));
1227        }
1228
1229        // Don't bother drawing empty range.
1230        if (rangeRect.isEmpty())
1231            continue;
1232
1233        IntPoint sliderTopLeft = rangeRect.location();
1234        IntPoint sliderTopRight = sliderTopLeft;
1235        sliderTopRight.move(0, rangeRect.height());
1236
1237        context->fillRect(FloatRect(rangeRect), m_mediaPanelColor, ColorSpaceDeviceRGB);
1238    }
1239    context->restore();
1240    return true;
1241}
1242
1243bool RenderThemeEfl::paintMediaSliderThumb(RenderObject*, const PaintInfo& info, const IntRect& rect)
1244{
1245    IntSize thumbRect(3, 3);
1246    info.context->fillRoundedRect(rect, thumbRect, thumbRect, thumbRect, thumbRect, m_sliderThumbColor, ColorSpaceDeviceRGB);
1247    return true;
1248}
1249
1250bool RenderThemeEfl::paintMediaVolumeSliderContainer(RenderObject*, const PaintInfo&, const IntRect&)
1251{
1252    notImplemented();
1253    return false;
1254}
1255
1256bool RenderThemeEfl::paintMediaVolumeSliderTrack(RenderObject*, const PaintInfo&, const IntRect&)
1257{
1258    notImplemented();
1259    return false;
1260}
1261
1262bool RenderThemeEfl::paintMediaVolumeSliderThumb(RenderObject*, const PaintInfo&, const IntRect&)
1263{
1264    notImplemented();
1265    return false;
1266}
1267
1268bool RenderThemeEfl::paintMediaCurrentTime(RenderObject*, const PaintInfo& info, const IntRect& rect)
1269{
1270    info.context->fillRect(FloatRect(rect), m_mediaPanelColor, ColorSpaceDeviceRGB);
1271    return true;
1272}
1273#endif
1274
1275#if ENABLE(VIDEO_TRACK)
1276bool RenderThemeEfl::supportsClosedCaptioning() const
1277{
1278    return true;
1279}
1280
1281bool RenderThemeEfl::paintMediaToggleClosedCaptionsButton(RenderObject* object, const PaintInfo& info, const IntRect& rect)
1282{
1283    Node* mediaNode = object->node() ? object->node()->shadowHost() : 0;
1284    if (!mediaNode)
1285        mediaNode = object->node();
1286    if (!mediaNode || (!mediaNode->hasTagName(videoTag)))
1287        return false;
1288
1289    HTMLMediaElement* mediaElement = static_cast<HTMLMediaElement*>(mediaNode);
1290    if (!emitMediaButtonSignal(ToggleCaptionsButton, mediaElement->webkitClosedCaptionsVisible() ? MediaShowClosedCaptionsButton : MediaHideClosedCaptionsButton, rect))
1291        return false;
1292
1293    return paintThemePart(object, ToggleCaptionsButton, info, rect);
1294}
1295#endif
1296
1297#undef _ASSERT_ON_RELEASE_RETURN
1298#undef _ASSERT_ON_RELEASE_RETURN_VAL
1299
1300}
1301