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 53namespace WebCore { 54#if ENABLE(VIDEO) 55using 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 62void 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 82bool 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 103bool 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 128struct 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 172struct 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 185struct 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) 202struct 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 233void 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 249void 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 271bool 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 345PassRefPtr<RenderTheme> RenderThemeEfl::create(Page* page) 346{ 347 return adoptRef(new RenderThemeEfl(page)); 348} 349 350PassRefPtr<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 359static 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 370static 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 381static 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 392static 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 403static 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 414static 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 425static 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 435void RenderThemeEfl::createCanvas() 436{ 437 ASSERT(!m_canvas); 438 m_canvas = ecore_evas_buffer_new(1, 1); 439 ASSERT(m_canvas); 440} 441 442void 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 481void 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 525void 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 536void 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 587const 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 620void 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 655void 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 675float RenderThemeEfl::defaultFontSize = 16.0f; 676 677RenderThemeEfl::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 700RenderThemeEfl::~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 711void 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 718void 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 725void 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 735void 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 742void 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 749void 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 756void 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 763static 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 782bool RenderThemeEfl::supportsFocusRing(const RenderStyle* style) const 783{ 784 return supportsFocus(style->appearance()); 785} 786 787bool RenderThemeEfl::controlSupportsTints(const RenderObject* object) const 788{ 789 return isEnabled(object); 790} 791 792int 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 804bool 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 811void 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 828void RenderThemeEfl::adjustSliderThumbStyle(CSSStyleSelector* selector, RenderStyle* style, Element* element) const 829{ 830 adjustSliderTrackStyle(selector, style, element); 831} 832 833bool RenderThemeEfl::paintSliderThumb(RenderObject* object, const PaintInfo& info, const IntRect& rect) 834{ 835 return paintSliderTrack(object, info, rect); 836} 837 838void 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 854bool RenderThemeEfl::paintCheckbox(RenderObject* object, const PaintInfo& info, const IntRect& rect) 855{ 856 return paintThemePart(object, CheckBox, info, rect); 857} 858 859void 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 875bool RenderThemeEfl::paintRadio(RenderObject* object, const PaintInfo& info, const IntRect& rect) 876{ 877 return paintThemePart(object, RadioButton, info, rect); 878} 879 880void 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 898bool RenderThemeEfl::paintButton(RenderObject* object, const PaintInfo& info, const IntRect& rect) 899{ 900 return paintThemePart(object, Button, info, rect); 901} 902 903void 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 916bool RenderThemeEfl::paintMenuList(RenderObject* object, const PaintInfo& info, const IntRect& rect) 917{ 918 return paintThemePart(object, ComboBox, info, rect); 919} 920 921void 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 934bool RenderThemeEfl::paintTextField(RenderObject* object, const PaintInfo& info, const IntRect& rect) 935{ 936 return paintThemePart(object, TextField, info, rect); 937} 938 939void RenderThemeEfl::adjustTextAreaStyle(CSSStyleSelector* selector, RenderStyle* style, Element* element) const 940{ 941 adjustTextFieldStyle(selector, style, element); 942} 943 944bool RenderThemeEfl::paintTextArea(RenderObject* object, const PaintInfo& info, const IntRect& rect) 945{ 946 return paintTextField(object, info, rect); 947} 948 949void 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 960bool RenderThemeEfl::paintSearchFieldDecoration(RenderObject* object, const PaintInfo& info, const IntRect& rect) 961{ 962 return paintThemePart(object, SearchFieldDecoration, info, rect); 963} 964 965void 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 976bool RenderThemeEfl::paintSearchFieldResultsButton(RenderObject* object, const PaintInfo& info, const IntRect& rect) 977{ 978 return paintThemePart(object, SearchFieldResultsButton, info, rect); 979} 980 981void 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 992bool RenderThemeEfl::paintSearchFieldResultsDecoration(RenderObject* object, const PaintInfo& info, const IntRect& rect) 993{ 994 return paintThemePart(object, SearchFieldResultsDecoration, info, rect); 995} 996 997void 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 1008bool RenderThemeEfl::paintSearchFieldCancelButton(RenderObject* object, const PaintInfo& info, const IntRect& rect) 1009{ 1010 return paintThemePart(object, SearchFieldCancelButton, info, rect); 1011} 1012 1013void 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 1026bool RenderThemeEfl::paintSearchField(RenderObject* object, const PaintInfo& info, const IntRect& rect) 1027{ 1028 return paintThemePart(object, SearchField, info, rect); 1029} 1030 1031void RenderThemeEfl::setDefaultFontSize(int size) 1032{ 1033 defaultFontSize = size; 1034} 1035 1036void 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) 1052void RenderThemeEfl::adjustProgressBarStyle(CSSStyleSelector* selector, RenderStyle* style, Element* element) const 1053{ 1054 style->setBoxShadow(0); 1055} 1056 1057bool 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) 1064bool 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 1091String RenderThemeEfl::extraMediaControlsStyleSheet() 1092{ 1093 return String(mediaControlsEflUserAgentStyleSheet, sizeof(mediaControlsEflUserAgentStyleSheet)); 1094} 1095 1096String RenderThemeEfl::formatMediaControlsCurrentTime(float currentTime, float duration) const 1097{ 1098 notImplemented(); 1099 return String(); 1100} 1101 1102bool RenderThemeEfl::paintMediaFullscreenButton(RenderObject* object, const PaintInfo& info, const IntRect& rect) 1103{ 1104 notImplemented(); 1105 return false; 1106} 1107 1108bool 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 1122bool 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 1135bool 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 1148bool 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 1161bool RenderThemeEfl::paintMediaSliderTrack(RenderObject* object, const PaintInfo& info, const IntRect& rect) 1162{ 1163 notImplemented(); 1164 return false; 1165} 1166 1167bool RenderThemeEfl::paintMediaSliderThumb(RenderObject* object, const PaintInfo& info, const IntRect& rect) 1168{ 1169 notImplemented(); 1170 return false; 1171} 1172 1173bool RenderThemeEfl::paintMediaVolumeSliderContainer(RenderObject*, const PaintInfo& info, const IntRect& rect) 1174{ 1175 notImplemented(); 1176 return false; 1177} 1178 1179bool RenderThemeEfl::paintMediaVolumeSliderTrack(RenderObject* object, const PaintInfo& info, const IntRect& rect) 1180{ 1181 notImplemented(); 1182 return false; 1183} 1184 1185bool RenderThemeEfl::paintMediaVolumeSliderThumb(RenderObject* object, const PaintInfo& info, const IntRect& rect) 1186{ 1187 notImplemented(); 1188 return false; 1189} 1190 1191bool RenderThemeEfl::paintMediaCurrentTime(RenderObject* object, const PaintInfo& info, const IntRect& rect) 1192{ 1193 notImplemented(); 1194 return false; 1195} 1196#endif 1197} 1198