1 /* 2 * Copyright (C) 2007 Apple Inc. 3 * Copyright (C) 2007 Alp Toker <alp (at) 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 } 1198