3ce50e3f2ce35e21e1a250821e77d320c73d61ed
[WebKit.git] / Source / WebCore / platform / efl / RenderThemeEfl.cpp
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  *
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.
13  *
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.
18  *
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.
23  *
24  */
25
26 #include "config.h"
27 #include "RenderThemeEfl.h"
28
29 #include "CSSValueKeywords.h"
30 #include "FileSystem.h"
31 #include "Frame.h"
32 #include "FrameView.h"
33 #include "GraphicsContext.h"
34 #include "NotImplemented.h"
35 #include "PaintInfo.h"
36 #include "Page.h"
37 #include "PlatformContextCairo.h"
38 #include "RenderBox.h"
39 #include "RenderObject.h"
40 #include "RenderProgress.h"
41 #include "RenderSlider.h"
42 #include "UserAgentStyleSheets.h"
43 #include <wtf/text/CString.h>
44
45 #include <Ecore_Evas.h>
46 #include <Edje.h>
47
48 #if ENABLE(VIDEO)
49 #include "HTMLMediaElement.h"
50 #include "HTMLNames.h"
51 #endif
52
53 namespace WebCore {
54 #if ENABLE(VIDEO)
55 using namespace HTMLNames;
56 #endif
57
58 // TODO: change from object count to ecore_evas size (bytes)
59 // TODO: as objects are webpage/user defined and they can be very large.
60 #define RENDER_THEME_EFL_PART_CACHE_MAX 32
61
62 void RenderThemeEfl::adjustSizeConstraints(RenderStyle* style, FormType type) const
63 {
64     const struct ThemePartDesc* desc = m_partDescs + (size_t)type;
65
66     if (style->minWidth().isIntrinsicOrAuto())
67         style->setMinWidth(desc->min.width());
68     if (style->minHeight().isIntrinsicOrAuto())
69         style->setMinHeight(desc->min.height());
70
71     if (desc->max.width().value() > 0 && style->maxWidth().isIntrinsicOrAuto())
72         style->setMaxWidth(desc->max.width());
73     if (desc->max.height().value() > 0 && style->maxHeight().isIntrinsicOrAuto())
74         style->setMaxHeight(desc->max.height());
75
76     style->setPaddingTop(desc->padding.top());
77     style->setPaddingBottom(desc->padding.bottom());
78     style->setPaddingLeft(desc->padding.left());
79     style->setPaddingRight(desc->padding.right());
80 }
81
82 bool RenderThemeEfl::themePartCacheEntryReset(struct ThemePartCacheEntry* entry, FormType type)
83 {
84     const char *file, *group;
85
86     ASSERT(entry);
87
88     edje_object_file_get(m_edje, &file, 0);
89     group = edjeGroupFromFormType(type);
90     ASSERT(file);
91     ASSERT(group);
92
93     if (!edje_object_file_set(entry->o, file, group)) {
94         Edje_Load_Error err = edje_object_load_error_get(entry->o);
95         const char *errmsg = edje_load_error_str(err);
96         EINA_LOG_ERR("Could not load '%s' from theme %s: %s",
97                      group, file, errmsg);
98         return false;
99     }
100     return true;
101 }
102
103 bool RenderThemeEfl::themePartCacheEntrySurfaceCreate(struct ThemePartCacheEntry* entry)
104 {
105     int w, h;
106     cairo_status_t status;
107
108     ASSERT(entry);
109     ASSERT(entry->ee);
110
111     ecore_evas_geometry_get(entry->ee, 0, 0, &w, &h);
112     ASSERT(w > 0);
113     ASSERT(h > 0);
114
115     entry->surface = cairo_image_surface_create_for_data((unsigned char *)ecore_evas_buffer_pixels_get(entry->ee),
116                                                       CAIRO_FORMAT_ARGB32, w, h, w * 4);
117     status = cairo_surface_status(entry->surface);
118     if (status != CAIRO_STATUS_SUCCESS) {
119         EINA_LOG_ERR("Could not create cairo surface: %s",
120                      cairo_status_to_string(status));
121         return false;
122     }
123
124     return true;
125 }
126
127 // allocate a new entry and fill it with edje group
128 struct RenderThemeEfl::ThemePartCacheEntry* RenderThemeEfl::cacheThemePartNew(FormType type, const IntSize& size)
129 {
130     struct ThemePartCacheEntry *entry = new struct ThemePartCacheEntry;
131
132     if (!entry) {
133         EINA_LOG_ERR("could not allocate ThemePartCacheEntry.");
134         return 0;
135     }
136
137     entry->ee = ecore_evas_buffer_new(size.width(), size.height());
138     if (!entry->ee) {
139         EINA_LOG_ERR("ecore_evas_buffer_new(%d, %d) failed.",
140                      size.width(), size.height());
141         delete entry;
142         return 0;
143     }
144
145     entry->o = edje_object_add(ecore_evas_get(entry->ee));
146     ASSERT(entry->o);
147     if (!themePartCacheEntryReset(entry, type)) {
148         evas_object_del(entry->o);
149         ecore_evas_free(entry->ee);
150         delete entry;
151         return 0;
152     }
153
154     if (!themePartCacheEntrySurfaceCreate(entry)) {
155         evas_object_del(entry->o);
156         ecore_evas_free(entry->ee);
157         delete entry;
158         return 0;
159     }
160
161     evas_object_resize(entry->o, size.width(), size.height());
162     evas_object_show(entry->o);
163
164     entry->type = type;
165     entry->size = size;
166
167     m_partCache.prepend(entry);
168     return entry;
169 }
170
171 // just change the edje group and return the same entry
172 struct RenderThemeEfl::ThemePartCacheEntry* RenderThemeEfl::cacheThemePartReset(FormType type, struct RenderThemeEfl::ThemePartCacheEntry* entry)
173 {
174     if (!themePartCacheEntryReset(entry, type)) {
175         entry->type = FormTypeLast; // invalidate
176         m_partCache.append(entry);
177         return 0;
178     }
179     entry->type = type;
180     m_partCache.prepend(entry);
181     return entry;
182 }
183
184 // resize entry and reset it
185 struct RenderThemeEfl::ThemePartCacheEntry* RenderThemeEfl::cacheThemePartResizeAndReset(FormType type, const IntSize& size, struct RenderThemeEfl::ThemePartCacheEntry* entry)
186 {
187     cairo_surface_finish(entry->surface);
188     ecore_evas_resize(entry->ee, size.width(), size.height());
189     evas_object_resize(entry->o, size.width(), size.height());
190
191     if (!themePartCacheEntrySurfaceCreate(entry)) {
192         evas_object_del(entry->o);
193         ecore_evas_free(entry->ee);
194         delete entry;
195         return 0;
196     }
197
198     return cacheThemePartReset(type, entry);
199 }
200
201 // general purpose get (will create, reuse and all)
202 struct RenderThemeEfl::ThemePartCacheEntry* RenderThemeEfl::cacheThemePartGet(FormType type, const IntSize& size)
203 {
204     Vector<struct ThemePartCacheEntry *>::iterator itr, end;
205     struct ThemePartCacheEntry *ce_last_size = 0;
206     int i, idxLastSize = -1;
207
208     itr = m_partCache.begin();
209     end = m_partCache.end();
210     for (i = 0; itr != end; i++, itr++) {
211         struct ThemePartCacheEntry *entry = *itr;
212         if (entry->size == size) {
213             if (entry->type == type)
214                 return entry;
215             ce_last_size = entry;
216             idxLastSize = i;
217         }
218     }
219
220     if (m_partCache.size() < RENDER_THEME_EFL_PART_CACHE_MAX)
221         return cacheThemePartNew(type, size);
222
223     if (ce_last_size && ce_last_size != m_partCache.first()) {
224         m_partCache.remove(idxLastSize);
225         return cacheThemePartReset(type, ce_last_size);
226     }
227
228     ThemePartCacheEntry* entry = m_partCache.last();
229     m_partCache.removeLast();
230     return cacheThemePartResizeAndReset(type, size, entry);
231 }
232
233 void RenderThemeEfl::cacheThemePartFlush()
234 {
235     Vector<struct ThemePartCacheEntry *>::iterator itr, end;
236
237     itr = m_partCache.begin();
238     end = m_partCache.end();
239     for (; itr != end; itr++) {
240         struct ThemePartCacheEntry *entry = *itr;
241         cairo_surface_finish(entry->surface);
242         evas_object_del(entry->o);
243         ecore_evas_free(entry->ee);
244         delete entry;
245     }
246     m_partCache.clear();
247 }
248
249 void RenderThemeEfl::applyEdjeStateFromForm(Evas_Object* object, ControlStates states)
250 {
251     const char *signals[] = { // keep in sync with WebCore/platform/ThemeTypes.h
252         "hovered",
253         "pressed",
254         "focused",
255         "enabled",
256         "checked",
257         "read-only",
258         "default",
259         "window-inactive",
260         "indeterminate"
261     };
262
263     edje_object_signal_emit(object, "reset", "");
264
265     for (size_t i = 0; i < WTF_ARRAY_LENGTH(signals); ++i) {
266         if (states & (1 << i))
267             edje_object_signal_emit(object, signals[i], "");
268     }
269 }
270
271 bool RenderThemeEfl::paintThemePart(RenderObject* object, FormType type, const PaintInfo& info, const IntRect& rect)
272 {
273     ThemePartCacheEntry* entry;
274     Eina_List* updates;
275     cairo_t* cairo;
276
277     ASSERT(m_canvas);
278     ASSERT(m_edje);
279
280     entry = cacheThemePartGet(type, rect.size());
281     ASSERT(entry);
282     if (!entry)
283         return false;
284
285     applyEdjeStateFromForm(entry->o, controlStatesForRenderer(object));
286
287     cairo = info.context->platformContext()->cr();
288     ASSERT(cairo);
289
290     // Currently, only sliders needs this message; if other widget ever needs special
291     // treatment, move them to special functions.
292     if (type == SliderVertical || type == SliderHorizontal) {
293         RenderSlider* renderSlider = toRenderSlider(object);
294         Edje_Message_Float_Set* msg;
295         int max, value;
296
297         if (type == SliderVertical) {
298             max = rect.height() - renderSlider->thumbRect().height();
299             value = renderSlider->thumbRect().y();
300         } else {
301             max = rect.width() - renderSlider->thumbRect().width();
302             value = renderSlider->thumbRect().x();
303         }
304
305         msg = static_cast<Edje_Message_Float_Set*>(alloca(sizeof(Edje_Message_Float_Set) + sizeof(float)));
306
307         msg->count = 2;
308         msg->val[0] = static_cast<float>(value) / static_cast<float>(max);
309         msg->val[1] = 0.1;
310         edje_object_message_send(entry->o, EDJE_MESSAGE_FLOAT_SET, 0, msg);
311 #if ENABLE(PROGRESS_TAG)
312     } else if (type == ProgressBar) {
313         RenderProgress* renderProgress = toRenderProgress(object);
314         Edje_Message_Float_Set* msg;
315         int max;
316         double value;
317
318         msg = static_cast<Edje_Message_Float_Set*>(alloca(sizeof(Edje_Message_Float_Set) + sizeof(float)));
319         max = rect.width();
320         value = renderProgress->position();
321
322         msg->count = 2;
323         if (object->style()->direction() == RTL)
324             msg->val[0] = (1.0 - value) * max;
325         else
326             msg->val[0] = 0;
327         msg->val[1] = value;
328         edje_object_message_send(entry->o, EDJE_MESSAGE_FLOAT_SET, 0, msg);
329 #endif
330     }
331
332     edje_object_calc_force(entry->o);
333     edje_object_message_signal_process(entry->o);
334     updates = evas_render_updates(ecore_evas_get(entry->ee));
335     evas_render_updates_free(updates);
336
337     cairo_save(cairo);
338     cairo_set_source_surface(cairo, entry->surface, rect.x(), rect.y());
339     cairo_paint_with_alpha(cairo, 1.0);
340     cairo_restore(cairo);
341
342     return false;
343 }
344
345 PassRefPtr<RenderTheme> RenderThemeEfl::create(Page* page)
346 {
347     return adoptRef(new RenderThemeEfl(page));
348 }
349
350 PassRefPtr<RenderTheme> RenderTheme::themeForPage(Page* page)
351 {
352     if (page)
353         return RenderThemeEfl::create(page);
354
355     static RenderTheme* fallback = RenderThemeEfl::create(0).releaseRef();
356     return fallback;
357 }
358
359 static void renderThemeEflColorClassSelectionActive(void* data, Evas_Object* object, const char* signal, const char* source)
360 {
361     RenderThemeEfl* that = static_cast<RenderThemeEfl *>(data);
362     int fr, fg, fb, fa, br, bg, bb, ba;
363
364     if (!edje_object_color_class_get(object, source, &fr, &fg, &fb, &fa, &br, &bg, &bb, &ba, 0, 0, 0, 0))
365         return;
366
367     that->setActiveSelectionColor(fr, fg, fb, fa, br, bg, bb, ba);
368 }
369
370 static void renderThemeEflColorClassSelectionInactive(void* data, Evas_Object* object, const char* signal, const char* source)
371 {
372     RenderThemeEfl* that = static_cast<RenderThemeEfl *>(data);
373     int fr, fg, fb, fa, br, bg, bb, ba;
374
375     if (!edje_object_color_class_get(object, source, &fr, &fg, &fb, &fa, &br, &bg, &bb, &ba, 0, 0, 0, 0))
376         return;
377
378     that->setInactiveSelectionColor(fr, fg, fb, fa, br, bg, bb, ba);
379 }
380
381 static void renderThemeEflColorClassFocusRing(void* data, Evas_Object* object, const char* signal, const char* source)
382 {
383     RenderThemeEfl* that = static_cast<RenderThemeEfl *>(data);
384     int fr, fg, fb, fa;
385
386     if (!edje_object_color_class_get(object, source, &fr, &fg, &fb, &fa, 0, 0, 0, 0, 0, 0, 0, 0))
387         return;
388
389     that->setFocusRingColor(fr, fg, fb, fa);
390 }
391
392 static void renderThemeEflColorClassButtonText(void* data, Evas_Object* object, const char* signal, const char* source)
393 {
394     RenderThemeEfl* that = static_cast<RenderThemeEfl *>(data);
395     int fr, fg, fb, fa, br, bg, bb, ba;
396
397     if (!edje_object_color_class_get(object, source, &fr, &fg, &fb, &fa, &br, &bg, &bb, &ba, 0, 0, 0, 0))
398         return;
399
400     that->setButtonTextColor(fr, fg, fb, fa, br, bg, bb, ba);
401 }
402
403 static void renderThemeEflColorClassComboText(void* data, Evas_Object* object, const char* signal, const char* source)
404 {
405     RenderThemeEfl* that = static_cast<RenderThemeEfl *>(data);
406     int fr, fg, fb, fa, br, bg, bb, ba;
407
408     if (!edje_object_color_class_get(object, source, &fr, &fg, &fb, &fa, &br, &bg, &bb, &ba, 0, 0, 0, 0))
409         return;
410
411     that->setComboTextColor(fr, fg, fb, fa, br, bg, bb, ba);
412 }
413
414 static void renderThemeEflColorClassEntryText(void* data, Evas_Object* object, const char* signal, const char* source)
415 {
416     RenderThemeEfl* that = static_cast<RenderThemeEfl *>(data);
417     int fr, fg, fb, fa, br, bg, bb, ba;
418
419     if (!edje_object_color_class_get(object, source, &fr, &fg, &fb, &fa, &br, &bg, &bb, &ba, 0, 0, 0, 0))
420         return;
421
422     that->setEntryTextColor(fr, fg, fb, fa, br, bg, bb, ba);
423 }
424
425 static void renderThemeEflColorClassSearchText(void* data, Evas_Object* object, const char* signal, const char* source)
426 {
427     RenderThemeEfl* that = static_cast<RenderThemeEfl *>(data);
428     int fr, fg, fb, fa, br, bg, bb, ba;
429     if (!edje_object_color_class_get(object, source, &fr, &fg, &fb, &fa, &br, &bg, &bb, &ba, 0, 0, 0, 0))
430         return;
431
432     that->setSearchTextColor(fr, fg, fb, fa, br, bg, bb, ba);
433 }
434
435 void RenderThemeEfl::createCanvas()
436 {
437     ASSERT(!m_canvas);
438     m_canvas = ecore_evas_buffer_new(1, 1);
439     ASSERT(m_canvas);
440 }
441
442 void RenderThemeEfl::createEdje()
443 {
444     ASSERT(!m_edje);
445     Frame* frame = m_page ? m_page->mainFrame() : 0;
446     FrameView* view = frame ? frame->view() : 0;
447     String theme = view ? view->edjeThemeRecursive() : "";
448     if (theme.isEmpty())
449         EINA_LOG_ERR("No theme defined, unable to set RenderThemeEfl.");
450     else {
451         m_edje = edje_object_add(ecore_evas_get(m_canvas));
452         if (!m_edje)
453             EINA_LOG_ERR("Could not create base edje object.");
454         else if (!edje_object_file_set(m_edje, theme.utf8().data(), "webkit/base")) {
455             Edje_Load_Error err = edje_object_load_error_get(m_edje);
456             const char* errmsg = edje_load_error_str(err);
457             EINA_LOG_ERR("Could not load 'webkit/base' from theme %s: %s",
458                          theme.utf8().data(), errmsg);
459             evas_object_del(m_edje);
460             m_edje = 0;
461         } else {
462 #define CONNECT(cc, func)                                               \
463             edje_object_signal_callback_add(m_edje, "color_class,set",  \
464                                             "webkit/"cc, func, this)
465
466             CONNECT("selection/active",
467                     renderThemeEflColorClassSelectionActive);
468             CONNECT("selection/inactive",
469                     renderThemeEflColorClassSelectionInactive);
470             CONNECT("focus_ring", renderThemeEflColorClassFocusRing);
471             CONNECT("button/text", renderThemeEflColorClassButtonText);
472             CONNECT("combo/text", renderThemeEflColorClassComboText);
473             CONNECT("entry/text", renderThemeEflColorClassEntryText);
474             CONNECT("search/text", renderThemeEflColorClassSearchText);
475 #undef CONNECT
476         }
477     }
478     ASSERT(m_edje);
479 }
480
481 void RenderThemeEfl::applyEdjeColors()
482 {
483     int fr, fg, fb, fa, br, bg, bb, ba;
484     ASSERT(m_edje);
485 #define COLOR_GET(cls)                                                  \
486     edje_object_color_class_get(m_edje, "webkit/"cls,                   \
487                                 &fr, &fg, &fb, &fa, &br, &bg, &bb, &ba, \
488                                 0, 0, 0, 0)
489
490     if (COLOR_GET("selection/active")) {
491         m_activeSelectionForegroundColor = Color(fr, fg, fb, fa);
492         m_activeSelectionBackgroundColor = Color(br, bg, bb, ba);
493     }
494     if (COLOR_GET("selection/inactive")) {
495         m_inactiveSelectionForegroundColor = Color(fr, fg, fb, fa);
496         m_inactiveSelectionBackgroundColor = Color(br, bg, bb, ba);
497     }
498     if (COLOR_GET("focus_ring")) {
499         m_focusRingColor = Color(fr, fg, fb, fa);
500         // webkit just use platformFocusRingColor() for default theme (without page)
501         // this is ugly, but no other way to do it unless we change
502         // it to use page themes as much as possible.
503         RenderTheme::setCustomFocusRingColor(m_focusRingColor);
504     }
505     if (COLOR_GET("button/text")) {
506         m_buttonTextForegroundColor = Color(fr, fg, fb, fa);
507         m_buttonTextBackgroundColor = Color(br, bg, bb, ba);
508     }
509     if (COLOR_GET("combo/text")) {
510         m_comboTextForegroundColor = Color(fr, fg, fb, fa);
511         m_comboTextBackgroundColor = Color(br, bg, bb, ba);
512     }
513     if (COLOR_GET("entry/text")) {
514         m_entryTextForegroundColor = Color(fr, fg, fb, fa);
515         m_entryTextBackgroundColor = Color(br, bg, bb, ba);
516     }
517     if (COLOR_GET("search/text")) {
518         m_searchTextForegroundColor = Color(fr, fg, fb, fa);
519         m_searchTextBackgroundColor = Color(br, bg, bb, ba);
520     }
521 #undef COLOR_GET
522     platformColorsDidChange();
523 }
524
525 void RenderThemeEfl::applyPartDescriptionFallback(struct ThemePartDesc* desc)
526 {
527     desc->min.setWidth(Length(0, Fixed));
528     desc->min.setHeight(Length(0, Fixed));
529
530     desc->max.setWidth(Length(0, Fixed));
531     desc->max.setHeight(Length(0, Fixed));
532
533     desc->padding = LengthBox(0, 0, 0, 0);
534 }
535
536 void RenderThemeEfl::applyPartDescription(Evas_Object* object, struct ThemePartDesc* desc)
537 {
538     Evas_Coord minw, minh, maxw, maxh;
539
540     edje_object_size_min_get(object, &minw, &minh);
541     if (!minw && !minh)
542         edje_object_size_min_calc(object, &minw, &minh);
543
544     desc->min.setWidth(Length(minw, Fixed));
545     desc->min.setHeight(Length(minh, Fixed));
546
547     edje_object_size_max_get(object, &maxw, &maxh);
548     desc->max.setWidth(Length(maxw, Fixed));
549     desc->max.setHeight(Length(maxh, Fixed));
550
551     if (!edje_object_part_exists(object, "text_confinement"))
552         desc->padding = LengthBox(0, 0, 0, 0);
553     else {
554         Evas_Coord px, py, pw, ph;
555         Evas_Coord ox = 0, oy = 0, ow = 0, oh = 0;
556         int t, r, b, l;
557
558         if (minw > 0)
559             ow = minw;
560         else
561             ow = 100;
562         if (minh > 0)
563             oh = minh;
564         else
565             oh = 100;
566         if (maxw > 0 && ow > maxw)
567             ow = maxw;
568         if (maxh > 0 && oh > maxh)
569             oh = maxh;
570
571         evas_object_move(object, ox, oy);
572         evas_object_resize(object, ow, oh);
573         edje_object_calc_force(object);
574         edje_object_message_signal_process(object);
575         edje_object_part_geometry_get(object, "text_confinement", &px, &py, &pw, &ph);
576
577         t = py - oy;
578         b = (oh + oy) - (ph + py);
579
580         l = px - ox;
581         r = (ow + ox) - (pw + px);
582
583         desc->padding = LengthBox(t, r, b, l);
584     }
585 }
586
587 const char* RenderThemeEfl::edjeGroupFromFormType(FormType type) const
588 {
589     static const char* groups[] = {
590 #define W(n) "webkit/widget/"n
591         W("button"),
592         W("radio"),
593         W("entry"),
594         W("checkbox"),
595         W("combo"),
596 #if ENABLE(PROGRESS_TAG)
597         W("progressbar"),
598 #endif
599         W("search/field"),
600         W("search/decoration"),
601         W("search/results_button"),
602         W("search/results_decoration"),
603         W("search/cancel_button"),
604         W("slider/vertical"),
605         W("slider/horizontal"),
606 #if ENABLE(VIDEO)
607         W("mediacontrol/playpause_button"),
608         W("mediacontrol/mute_button"),
609         W("mediacontrol/seekforward_button"),
610         W("mediacontrol/seekbackward_button"),
611 #endif
612 #undef W
613         0
614     };
615     ASSERT(type >= 0);
616     ASSERT((size_t)type < sizeof(groups) / sizeof(groups[0])); // out of sync?
617     return groups[type];
618 }
619
620 void RenderThemeEfl::applyPartDescriptions()
621 {
622     Evas_Object* object;
623     unsigned int i;
624     const char* file;
625
626     ASSERT(m_canvas);
627     ASSERT(m_edje);
628
629     edje_object_file_get(m_edje, &file, 0);
630     ASSERT(file);
631
632     object = edje_object_add(ecore_evas_get(m_canvas));
633     if (!object) {
634         EINA_LOG_ERR("Could not create Edje object.");
635         return;
636     }
637
638     for (i = 0; i < FormTypeLast; i++) {
639         FormType type = static_cast<FormType>(i);
640         const char* group = edjeGroupFromFormType(type);
641         m_partDescs[i].type = type;
642         if (!edje_object_file_set(object, file, group)) {
643             Edje_Load_Error err = edje_object_load_error_get(object);
644             const char* errmsg = edje_load_error_str(err);
645             EINA_LOG_ERR("Could not set theme group '%s' of file '%s': %s",
646                          group, file, errmsg);
647
648             applyPartDescriptionFallback(m_partDescs + i);
649         } else
650             applyPartDescription(object, m_partDescs + i);
651     }
652     evas_object_del(object);
653 }
654
655 void RenderThemeEfl::themeChanged()
656 {
657     cacheThemePartFlush();
658
659     if (!m_canvas) {
660         createCanvas();
661         if (!m_canvas)
662             return;
663     }
664
665     if (!m_edje) {
666         createEdje();
667         if (!m_edje)
668             return;
669     }
670
671     applyEdjeColors();
672     applyPartDescriptions();
673 }
674
675 float RenderThemeEfl::defaultFontSize = 16.0f;
676
677 RenderThemeEfl::RenderThemeEfl(Page* page)
678     : RenderTheme()
679     , m_page(page)
680     , m_activeSelectionBackgroundColor(0, 0, 255)
681     , m_activeSelectionForegroundColor(255, 255, 255)
682     , m_inactiveSelectionBackgroundColor(0, 0, 128)
683     , m_inactiveSelectionForegroundColor(200, 200, 200)
684     , m_focusRingColor(32, 32, 224, 224)
685     , m_buttonTextBackgroundColor(0, 0, 0, 0)
686     , m_buttonTextForegroundColor(0, 0, 0)
687     , m_comboTextBackgroundColor(0, 0, 0, 0)
688     , m_comboTextForegroundColor(0, 0, 0)
689     , m_entryTextBackgroundColor(0, 0, 0, 0)
690     , m_entryTextForegroundColor(0, 0, 0)
691     , m_searchTextBackgroundColor(0, 0, 0, 0)
692     , m_searchTextForegroundColor(0, 0, 0)
693     , m_canvas(0)
694     , m_edje(0)
695 {
696     if (page && page->mainFrame() && page->mainFrame()->view())
697         themeChanged();
698 }
699
700 RenderThemeEfl::~RenderThemeEfl()
701 {
702     cacheThemePartFlush();
703
704     if (m_canvas) {
705         if (m_edje)
706             evas_object_del(m_edje);
707         ecore_evas_free(m_canvas);
708     }
709 }
710
711 void RenderThemeEfl::setActiveSelectionColor(int foreR, int foreG, int foreB, int foreA, int backR, int backG, int backB, int backA)
712 {
713     m_activeSelectionForegroundColor = Color(foreR, foreG, foreB, foreA);
714     m_activeSelectionBackgroundColor = Color(backR, backG, backB, backA);
715     platformColorsDidChange();
716 }
717
718 void RenderThemeEfl::setInactiveSelectionColor(int foreR, int foreG, int foreB, int foreA, int backR, int backG, int backB, int backA)
719 {
720     m_inactiveSelectionForegroundColor = Color(foreR, foreG, foreB, foreA);
721     m_inactiveSelectionBackgroundColor = Color(backR, backG, backB, backA);
722     platformColorsDidChange();
723 }
724
725 void RenderThemeEfl::setFocusRingColor(int r, int g, int b, int a)
726 {
727     m_focusRingColor = Color(r, g, b, a);
728     // webkit just use platformFocusRingColor() for default theme (without page)
729     // this is ugly, but no other way to do it unless we change
730     // it to use page themes as much as possible.
731     RenderTheme::setCustomFocusRingColor(m_focusRingColor);
732     platformColorsDidChange();
733 }
734
735 void RenderThemeEfl::setButtonTextColor(int foreR, int foreG, int foreB, int foreA, int backR, int backG, int backB, int backA)
736 {
737     m_buttonTextForegroundColor = Color(foreR, foreG, foreB, foreA);
738     m_buttonTextBackgroundColor = Color(backR, backG, backB, backA);
739     platformColorsDidChange();
740 }
741
742 void RenderThemeEfl::setComboTextColor(int foreR, int foreG, int foreB, int foreA, int backR, int backG, int backB, int backA)
743 {
744     m_comboTextForegroundColor = Color(foreR, foreG, foreB, foreA);
745     m_comboTextBackgroundColor = Color(backR, backG, backB, backA);
746     platformColorsDidChange();
747 }
748
749 void RenderThemeEfl::setEntryTextColor(int foreR, int foreG, int foreB, int foreA, int backR, int backG, int backB, int backA)
750 {
751     m_entryTextForegroundColor = Color(foreR, foreG, foreB, foreA);
752     m_entryTextBackgroundColor = Color(backR, backG, backB, backA);
753     platformColorsDidChange();
754 }
755
756 void RenderThemeEfl::setSearchTextColor(int foreR, int foreG, int foreB, int foreA, int backR, int backG, int backB, int backA)
757 {
758     m_searchTextForegroundColor = Color(foreR, foreG, foreB, foreA);
759     m_searchTextBackgroundColor = Color(backR, backG, backB, backA);
760     platformColorsDidChange();
761 }
762
763 static bool supportsFocus(ControlPart appearance)
764 {
765     switch (appearance) {
766     case PushButtonPart:
767     case ButtonPart:
768     case TextFieldPart:
769     case TextAreaPart:
770     case SearchFieldPart:
771     case MenulistPart:
772     case RadioPart:
773     case CheckboxPart:
774     case SliderVerticalPart:
775     case SliderHorizontalPart:
776         return true;
777     default:
778         return false;
779     }
780 }
781
782 bool RenderThemeEfl::supportsFocusRing(const RenderStyle* style) const
783 {
784     return supportsFocus(style->appearance());
785 }
786
787 bool RenderThemeEfl::controlSupportsTints(const RenderObject* object) const
788 {
789     return isEnabled(object);
790 }
791
792 int RenderThemeEfl::baselinePosition(const RenderObject* object) const
793 {
794     if (!object->isBox())
795         return 0;
796
797     if (object->style()->appearance() == CheckboxPart
798     ||  object->style()->appearance() == RadioPart)
799         return toRenderBox(object)->marginTop() + toRenderBox(object)->height() - 3;
800
801     return RenderTheme::baselinePosition(object);
802 }
803
804 bool RenderThemeEfl::paintSliderTrack(RenderObject* object, const PaintInfo& info, const IntRect& rect)
805 {
806     if (object->style()->appearance() == SliderHorizontalPart)
807         return paintThemePart(object, SliderHorizontal, info, rect);
808     return paintThemePart(object, SliderVertical, info, rect);
809 }
810
811 void RenderThemeEfl::adjustSliderTrackStyle(CSSStyleSelector* selector, RenderStyle* style, Element* element) const
812 {
813     if (!m_page && element && element->document()->page()) {
814         static_cast<RenderThemeEfl*>(element->document()->page()->theme())->adjustSliderTrackStyle(selector, style, element);
815         return;
816     }
817
818     adjustSizeConstraints(style, SliderHorizontal);
819     style->resetBorder();
820
821     const struct ThemePartDesc *desc = m_partDescs + (size_t)SliderHorizontal;
822     if (style->width().value() < desc->min.width().value())
823         style->setWidth(desc->min.width());
824     if (style->height().value() < desc->min.height().value())
825         style->setHeight(desc->min.height());
826 }
827
828 void RenderThemeEfl::adjustSliderThumbStyle(CSSStyleSelector* selector, RenderStyle* style, Element* element) const
829 {
830     adjustSliderTrackStyle(selector, style, element);
831 }
832
833 bool RenderThemeEfl::paintSliderThumb(RenderObject* object, const PaintInfo& info, const IntRect& rect)
834 {
835     return paintSliderTrack(object, info, rect);
836 }
837
838 void RenderThemeEfl::adjustCheckboxStyle(CSSStyleSelector* selector, RenderStyle* style, Element* element) const
839 {
840     if (!m_page && element && element->document()->page()) {
841         static_cast<RenderThemeEfl*>(element->document()->page()->theme())->adjustCheckboxStyle(selector, style, element);
842         return;
843     }
844     adjustSizeConstraints(style, CheckBox);
845     style->resetBorder();
846
847     const struct ThemePartDesc *desc = m_partDescs + (size_t)CheckBox;
848     if (style->width().value() < desc->min.width().value())
849         style->setWidth(desc->min.width());
850     if (style->height().value() < desc->min.height().value())
851         style->setHeight(desc->min.height());
852 }
853
854 bool RenderThemeEfl::paintCheckbox(RenderObject* object, const PaintInfo& info, const IntRect& rect)
855 {
856     return paintThemePart(object, CheckBox, info, rect);
857 }
858
859 void RenderThemeEfl::adjustRadioStyle(CSSStyleSelector* selector, RenderStyle* style, Element* element) const
860 {
861     if (!m_page && element && element->document()->page()) {
862         static_cast<RenderThemeEfl*>(element->document()->page()->theme())->adjustRadioStyle(selector, style, element);
863         return;
864     }
865     adjustSizeConstraints(style, RadioButton);
866     style->resetBorder();
867
868     const struct ThemePartDesc *desc = m_partDescs + (size_t)RadioButton;
869     if (style->width().value() < desc->min.width().value())
870         style->setWidth(desc->min.width());
871     if (style->height().value() < desc->min.height().value())
872         style->setHeight(desc->min.height());
873 }
874
875 bool RenderThemeEfl::paintRadio(RenderObject* object, const PaintInfo& info, const IntRect& rect)
876 {
877     return paintThemePart(object, RadioButton, info, rect);
878 }
879
880 void RenderThemeEfl::adjustButtonStyle(CSSStyleSelector* selector, RenderStyle* style, Element* element) const
881 {
882     if (!m_page && element && element->document()->page()) {
883         static_cast<RenderThemeEfl*>(element->document()->page()->theme())->adjustButtonStyle(selector, style, element);
884         return;
885     }
886
887     adjustSizeConstraints(style, Button);
888
889     if (style->appearance() == PushButtonPart) {
890         style->resetBorder();
891         style->setWhiteSpace(PRE);
892         style->setHeight(Length(Auto));
893         style->setColor(m_buttonTextForegroundColor);
894         style->setBackgroundColor(m_buttonTextBackgroundColor);
895     }
896 }
897
898 bool RenderThemeEfl::paintButton(RenderObject* object, const PaintInfo& info, const IntRect& rect)
899 {
900     return paintThemePart(object, Button, info, rect);
901 }
902
903 void RenderThemeEfl::adjustMenuListStyle(CSSStyleSelector* selector, RenderStyle* style, Element* element) const
904 {
905     if (!m_page && element && element->document()->page()) {
906         static_cast<RenderThemeEfl*>(element->document()->page()->theme())->adjustMenuListStyle(selector, style, element);
907         return;
908     }
909     adjustSizeConstraints(style, ComboBox);
910     style->resetBorder();
911     style->setWhiteSpace(PRE);
912     style->setColor(m_comboTextForegroundColor);
913     style->setBackgroundColor(m_comboTextBackgroundColor);
914 }
915
916 bool RenderThemeEfl::paintMenuList(RenderObject* object, const PaintInfo& info, const IntRect& rect)
917 {
918     return paintThemePart(object, ComboBox, info, rect);
919 }
920
921 void RenderThemeEfl::adjustTextFieldStyle(CSSStyleSelector* selector, RenderStyle* style, Element* element) const
922 {
923     if (!m_page && element && element->document()->page()) {
924         static_cast<RenderThemeEfl*>(element->document()->page()->theme())->adjustTextFieldStyle(selector, style, element);
925         return;
926     }
927     adjustSizeConstraints(style, TextField);
928     style->resetBorder();
929     style->setWhiteSpace(PRE);
930     style->setColor(m_entryTextForegroundColor);
931     style->setBackgroundColor(m_entryTextBackgroundColor);
932 }
933
934 bool RenderThemeEfl::paintTextField(RenderObject* object, const PaintInfo& info, const IntRect& rect)
935 {
936     return paintThemePart(object, TextField, info, rect);
937 }
938
939 void RenderThemeEfl::adjustTextAreaStyle(CSSStyleSelector* selector, RenderStyle* style, Element* element) const
940 {
941     adjustTextFieldStyle(selector, style, element);
942 }
943
944 bool RenderThemeEfl::paintTextArea(RenderObject* object, const PaintInfo& info, const IntRect& rect)
945 {
946     return paintTextField(object, info, rect);
947 }
948
949 void RenderThemeEfl::adjustSearchFieldDecorationStyle(CSSStyleSelector* selector, RenderStyle* style, Element* element) const
950 {
951     if (!m_page && element && element->document()->page()) {
952         static_cast<RenderThemeEfl*>(element->document()->page()->theme())->adjustSearchFieldDecorationStyle(selector, style, element);
953         return;
954     }
955     adjustSizeConstraints(style, SearchFieldDecoration);
956     style->resetBorder();
957     style->setWhiteSpace(PRE);
958 }
959
960 bool RenderThemeEfl::paintSearchFieldDecoration(RenderObject* object, const PaintInfo& info, const IntRect& rect)
961 {
962     return paintThemePart(object, SearchFieldDecoration, info, rect);
963 }
964
965 void RenderThemeEfl::adjustSearchFieldResultsButtonStyle(CSSStyleSelector* selector, RenderStyle* style, Element* element) const
966 {
967     if (!m_page && element && element->document()->page()) {
968         static_cast<RenderThemeEfl*>(element->document()->page()->theme())->adjustSearchFieldResultsButtonStyle(selector, style, element);
969         return;
970     }
971     adjustSizeConstraints(style, SearchFieldResultsButton);
972     style->resetBorder();
973     style->setWhiteSpace(PRE);
974 }
975
976 bool RenderThemeEfl::paintSearchFieldResultsButton(RenderObject* object, const PaintInfo& info, const IntRect& rect)
977 {
978     return paintThemePart(object, SearchFieldResultsButton, info, rect);
979 }
980
981 void RenderThemeEfl::adjustSearchFieldResultsDecorationStyle(CSSStyleSelector* selector, RenderStyle* style, Element* element) const
982 {
983     if (!m_page && element && element->document()->page()) {
984         static_cast<RenderThemeEfl*>(element->document()->page()->theme())->adjustSearchFieldResultsDecorationStyle(selector, style, element);
985         return;
986     }
987     adjustSizeConstraints(style, SearchFieldResultsDecoration);
988     style->resetBorder();
989     style->setWhiteSpace(PRE);
990 }
991
992 bool RenderThemeEfl::paintSearchFieldResultsDecoration(RenderObject* object, const PaintInfo& info, const IntRect& rect)
993 {
994     return paintThemePart(object, SearchFieldResultsDecoration, info, rect);
995 }
996
997 void RenderThemeEfl::adjustSearchFieldCancelButtonStyle(CSSStyleSelector* selector, RenderStyle* style, Element* element) const
998 {
999     if (!m_page && element && element->document()->page()) {
1000         static_cast<RenderThemeEfl*>(element->document()->page()->theme())->adjustSearchFieldCancelButtonStyle(selector, style, element);
1001         return;
1002     }
1003     adjustSizeConstraints(style, SearchFieldCancelButton);
1004     style->resetBorder();
1005     style->setWhiteSpace(PRE);
1006 }
1007
1008 bool RenderThemeEfl::paintSearchFieldCancelButton(RenderObject* object, const PaintInfo& info, const IntRect& rect)
1009 {
1010     return paintThemePart(object, SearchFieldCancelButton, info, rect);
1011 }
1012
1013 void RenderThemeEfl::adjustSearchFieldStyle(CSSStyleSelector* selector, RenderStyle* style, Element* element) const
1014 {
1015     if (!m_page && element && element->document()->page()) {
1016         static_cast<RenderThemeEfl*>(element->document()->page()->theme())->adjustSearchFieldStyle(selector, style, element);
1017         return;
1018     }
1019     adjustSizeConstraints(style, SearchField);
1020     style->resetBorder();
1021     style->setWhiteSpace(PRE);
1022     style->setColor(m_searchTextForegroundColor);
1023     style->setBackgroundColor(m_searchTextBackgroundColor);
1024 }
1025
1026 bool RenderThemeEfl::paintSearchField(RenderObject* object, const PaintInfo& info, const IntRect& rect)
1027 {
1028     return paintThemePart(object, SearchField, info, rect);
1029 }
1030
1031 void RenderThemeEfl::setDefaultFontSize(int size)
1032 {
1033     defaultFontSize = size;
1034 }
1035
1036 void RenderThemeEfl::systemFont(int propId, FontDescription& fontDescription) const
1037 {
1038     // It was called by RenderEmbeddedObject::paintReplaced to render alternative string.
1039     // To avoid cairo_error while rendering, fontDescription should be passed.
1040     DEFINE_STATIC_LOCAL(String, fontFace, ("Sans"));
1041     float fontSize = defaultFontSize;
1042
1043     fontDescription.firstFamily().setFamily(fontFace);
1044     fontDescription.setSpecifiedSize(fontSize);
1045     fontDescription.setIsAbsoluteSize(true);
1046     fontDescription.setGenericFamily(FontDescription::NoFamily);
1047     fontDescription.setWeight(FontWeightNormal);
1048     fontDescription.setItalic(false);
1049 }
1050
1051 #if ENABLE(PROGRESS_TAG)
1052 void RenderThemeEfl::adjustProgressBarStyle(CSSStyleSelector* selector, RenderStyle* style, Element* element) const
1053 {
1054     style->setBoxShadow(0);
1055 }
1056
1057 bool RenderThemeEfl::paintProgressBar(RenderObject* object, const PaintInfo& info, const IntRect& rect)
1058 {
1059     return paintThemePart(object, ProgressBar, info, rect);
1060 }
1061 #endif
1062
1063 #if ENABLE(VIDEO)
1064 bool RenderThemeEfl::emitMediaButtonSignal(FormType formType, MediaControlElementType mediaElementType, const IntRect& rect)
1065 {
1066     ThemePartCacheEntry* entry;
1067
1068     entry = cacheThemePartGet(formType, rect.size());
1069     ASSERT(entry);
1070     if (!entry)
1071         return false;
1072
1073     if (mediaElementType == MediaPlayButton)
1074         edje_object_signal_emit(entry->o, "play", "");
1075     else if (mediaElementType == MediaPauseButton)
1076         edje_object_signal_emit(entry->o, "pause", "");
1077     else if (mediaElementType == MediaMuteButton)
1078         edje_object_signal_emit(entry->o, "mute", "");
1079     else if (mediaElementType == MediaUnMuteButton)
1080         edje_object_signal_emit(entry->o, "sound", "");
1081     else if (mediaElementType == MediaSeekForwardButton)
1082         edje_object_signal_emit(entry->o, "seekforward", "");
1083     else if (mediaElementType == MediaSeekBackButton)
1084         edje_object_signal_emit(entry->o, "seekbackward", "");
1085     else
1086         return false;
1087
1088     return true;
1089 }
1090
1091 String RenderThemeEfl::extraMediaControlsStyleSheet()
1092 {
1093     return String(mediaControlsEflUserAgentStyleSheet, sizeof(mediaControlsEflUserAgentStyleSheet));
1094 }
1095
1096 String RenderThemeEfl::formatMediaControlsCurrentTime(float currentTime, float duration) const
1097 {
1098     notImplemented();
1099     return String();
1100 }
1101
1102 bool RenderThemeEfl::paintMediaFullscreenButton(RenderObject* object, const PaintInfo& info, const IntRect& rect)
1103 {
1104     notImplemented();
1105     return false;
1106 }
1107
1108 bool RenderThemeEfl::paintMediaMuteButton(RenderObject* object, const PaintInfo& info, const IntRect& rect)
1109 {
1110     Node* mediaNode = object->node() ? object->node()->shadowAncestorNode() : 0;
1111     if (!mediaNode || (!mediaNode->hasTagName(videoTag) && !mediaNode->hasTagName(audioTag)))
1112         return false;
1113
1114     HTMLMediaElement* mediaElement = static_cast<HTMLMediaElement*>(mediaNode);
1115
1116     if (!emitMediaButtonSignal(MuteUnMuteButton, mediaElement->muted() ? MediaMuteButton : MediaUnMuteButton, rect))
1117         return false;
1118
1119     return paintThemePart(object, MuteUnMuteButton, info, rect);
1120 }
1121
1122 bool RenderThemeEfl::paintMediaPlayButton(RenderObject* object, const PaintInfo& info, const IntRect& rect)
1123 {
1124     Node* node = object->node();
1125     if (!node || !node->isMediaControlElement())
1126         return false;
1127
1128     MediaControlPlayButtonElement* button = static_cast<MediaControlPlayButtonElement*>(node);
1129     if (!emitMediaButtonSignal(PlayPauseButton, button->displayType(), rect))
1130         return false;
1131
1132     return paintThemePart(object, PlayPauseButton, info, rect);
1133 }
1134
1135 bool RenderThemeEfl::paintMediaSeekBackButton(RenderObject* object, const PaintInfo& info, const IntRect& rect)
1136 {
1137     Node* node = object->node();
1138     if (!node || !node->isMediaControlElement())
1139         return 0;
1140
1141     MediaControlSeekButtonElement* button = static_cast<MediaControlSeekButtonElement*>(node);
1142     if (!emitMediaButtonSignal(SeekBackwardButton, button->displayType(), rect))
1143         return false;
1144
1145     return paintThemePart(object, SeekBackwardButton, info, rect);
1146 }
1147
1148 bool RenderThemeEfl::paintMediaSeekForwardButton(RenderObject* object, const PaintInfo& info, const IntRect& rect)
1149 {
1150     Node* node = object->node();
1151     if (!node || !node->isMediaControlElement())
1152         return 0;
1153
1154     MediaControlSeekButtonElement* button = static_cast<MediaControlSeekButtonElement*>(node);
1155     if (!emitMediaButtonSignal(SeekForwardButton, button->displayType(), rect))
1156         return false;
1157
1158     return paintThemePart(object, SeekForwardButton, info, rect);
1159 }
1160
1161 bool RenderThemeEfl::paintMediaSliderTrack(RenderObject* object, const PaintInfo& info, const IntRect& rect)
1162 {
1163     notImplemented();
1164     return false;
1165 }
1166
1167 bool RenderThemeEfl::paintMediaSliderThumb(RenderObject* object, const PaintInfo& info, const IntRect& rect)
1168 {
1169     notImplemented();
1170     return false;
1171 }
1172
1173 bool RenderThemeEfl::paintMediaVolumeSliderContainer(RenderObject*, const PaintInfo& info, const IntRect& rect)
1174 {
1175     notImplemented();
1176     return false;
1177 }
1178
1179 bool RenderThemeEfl::paintMediaVolumeSliderTrack(RenderObject* object, const PaintInfo& info, const IntRect& rect)
1180 {
1181     notImplemented();
1182     return false;
1183 }
1184
1185 bool RenderThemeEfl::paintMediaVolumeSliderThumb(RenderObject* object, const PaintInfo& info, const IntRect& rect)
1186 {
1187     notImplemented();
1188     return false;
1189 }
1190
1191 bool RenderThemeEfl::paintMediaCurrentTime(RenderObject* object, const PaintInfo& info, const IntRect& rect)
1192 {
1193     notImplemented();
1194     return false;
1195 }
1196 #endif
1197 }