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