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