1 /*
   2  * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 #include "config.h"
  27 
  28 #include <cstdio>
  29 #include <wtf/Vector.h>
  30 #include <wtf/text/StringBuilder.h>
  31 
  32 #include "Chrome.h"
  33 #include "ChromeClientJava.h"
  34 #include "CSSPropertyNames.h"
  35 #include "CSSFontSelector.h"
  36 #include "CSSValueKeywords.h"
  37 #include <wtf/java/JavaEnv.h>
  38 #include "HTMLMediaElement.h"
  39 #include "NotImplemented.h"
  40 #include "PaintInfo.h"
  41 #include "PlatformContextJava.h"
  42 #include "RenderObject.h"
  43 #if ENABLE(PROGRESS_ELEMENT)
  44 #include "RenderProgress.h"
  45 #endif
  46 #if ENABLE(METER_ELEMENT)
  47 #include "HTMLMeterElement.h"
  48 #endif
  49 #include "RenderSlider.h"
  50 #include "RenderThemeJava.h"
  51 #include "ThemeTypes.h"
  52 #include "TimeRanges.h"
  53 #include "UserAgentScripts.h"
  54 #include "UserAgentStyleSheets.h"
  55 #include "MediaControlElementTypes.h"
  56 #include "Page.h"
  57 
  58 #include "com_sun_webkit_graphics_RenderTheme.h"
  59 #include "com_sun_webkit_graphics_GraphicsDecoder.h"
  60 #include "com_sun_webkit_graphics_RenderMediaControls.h"
  61 
  62 
  63 #define RENDER_MEDIA_CONTROLS_CLASS_NAME    "com/sun/webkit/graphics/RenderMediaControls"
  64 
  65 #define JNI_EXPAND(n) com_sun_webkit_graphics_RenderTheme_##n
  66 #define JNI_EXPAND_MEDIA(n) com_sun_webkit_graphics_RenderMediaControls_##n
  67 
  68 namespace WebCore {
  69 
  70 RenderTheme& RenderTheme::singleton()
  71 {
  72     static RenderTheme& sm_defaultInstance = *new RenderThemeJava();
  73     return sm_defaultInstance;
  74 }
  75 
  76 jclass getJRenderThemeClass()
  77 {
  78     static JGClass jRenderThemeCls(
  79         WebCore_GetJavaEnv()->FindClass("com/sun/webkit/graphics/RenderTheme"));
  80     ASSERT(jRenderThemeCls);
  81 
  82     return jRenderThemeCls;
  83 }
  84 
  85 static JLObject getJRenderTheme(JLObject page)
  86 {
  87     JNIEnv* env = WebCore_GetJavaEnv();
  88 
  89     if (!page) {
  90         static jmethodID mid  = env->GetStaticMethodID(
  91             PG_GetWebPageClass(env),
  92             "fwkGetDefaultRenderTheme",
  93             "()Lcom/sun/webkit/graphics/RenderTheme;");
  94         ASSERT(mid);
  95 
  96         JLObject jRenderTheme(env->CallStaticObjectMethod(PG_GetWebPageClass(env), mid));
  97         CheckAndClearException(env);
  98 
  99         return jRenderTheme;
 100     }
 101 
 102     static jmethodID mid  = env->GetMethodID(
 103         PG_GetWebPageClass(env),
 104         "getRenderTheme",
 105         "()Lcom/sun/webkit/graphics/RenderTheme;");
 106     ASSERT(mid);
 107 
 108     JLObject jRenderTheme(env->CallObjectMethod(
 109         page,
 110         mid));
 111     CheckAndClearException(env);
 112 
 113     return jRenderTheme;
 114 }
 115 
 116 RefPtr<RQRef> RenderThemeJava::themeForPage(JLObject page)
 117 {
 118     return RQRef::create(getJRenderTheme(page));
 119 }
 120 
 121 RenderThemeJava::RenderThemeJava()
 122 {
 123 }
 124 
 125 int RenderThemeJava::createWidgetState(const RenderObject& o)
 126 {
 127     int state = 0;
 128     if (isChecked(o))
 129         state |= JNI_EXPAND(CHECKED);
 130     if (isIndeterminate(o))
 131         state |= JNI_EXPAND(INDETERMINATE);
 132     if (isEnabled(o))
 133         state |= JNI_EXPAND(ENABLED);
 134     if (isFocused(o))
 135         state |= JNI_EXPAND(FOCUSED);
 136     if (isPressed(o))
 137         state |= JNI_EXPAND(PRESSED);
 138     if (isHovered(o))
 139         state |= JNI_EXPAND(HOVERED);
 140     if (isReadOnlyControl(o))
 141         state |= JNI_EXPAND(READ_ONLY);
 142     return state;
 143 }
 144 
 145 bool RenderThemeJava::paintWidget(
 146     int widgetIndex,
 147     const RenderObject& object,
 148     const PaintInfo &paintInfo,
 149     const FloatRect &rect) {
 150 
 151     return paintWidget(widgetIndex, object, paintInfo, enclosingIntRect(rect));
 152 }
 153 
 154 bool RenderThemeJava::paintWidget(
 155     int widgetIndex,
 156     const RenderObject& object,
 157     const PaintInfo &paintInfo,
 158     const IntRect &rect)
 159 {
 160     // platformContext() returns 0 when printing
 161     if (paintInfo.context().paintingDisabled() || !paintInfo.context().platformContext()) {
 162         return false;
 163     }
 164 
 165     auto jRenderTheme = paintInfo.context().platformContext()->jRenderTheme();
 166     if (!jRenderTheme) {
 167         return false;
 168     }
 169 
 170     int state = createWidgetState(object);
 171     RGBA32 bgColor = object.style().visitedDependentColor(
 172         widgetIndex == JNI_EXPAND(MENU_LIST_BUTTON)
 173             ? CSSPropertyColor
 174             : CSSPropertyBackgroundColor
 175     ).rgb();
 176 
 177     JNIEnv* env = WebCore_GetJavaEnv();
 178 
 179     WTF::Vector<jbyte> extParams;
 180     if (JNI_EXPAND(SLIDER) == widgetIndex && is<RenderSlider>(object)) {
 181         HTMLInputElement& input = downcast<RenderSlider>(object).element();
 182 
 183         extParams.grow(sizeof(jint) + 3 * sizeof(jfloat));
 184         jbyte *data = extParams.data();
 185         auto isVertical = jint((object.style().appearance() == SliderHorizontalPart)
 186             ? 0
 187             : 1);
 188         memcpy(data, &isVertical, sizeof(isVertical));
 189         data += sizeof(jint);
 190 
 191         auto maximum = jfloat(input.maximum());
 192         memcpy(data, &maximum, sizeof(maximum));
 193         data += sizeof(jfloat);
 194 
 195         auto minimum = jfloat(input.minimum());
 196         memcpy(data, &minimum, sizeof(minimum));
 197         data += sizeof(jfloat);
 198 
 199         auto valueAsNumber = jfloat(input.valueAsNumber());
 200         memcpy(data, &valueAsNumber, sizeof(valueAsNumber));
 201     } else if (JNI_EXPAND(PROGRESS_BAR) == widgetIndex) {
 202 #if ENABLE(PROGRESS_ELEMENT)
 203         if (is<RenderProgress>(object)) {
 204             RenderProgress& renderProgress = downcast<RenderProgress>(object);
 205 
 206             extParams.grow(sizeof(jint) + 3*sizeof(jfloat));
 207             jbyte *data = extParams.data();
 208             auto isDeterminate = jint(renderProgress.isDeterminate() ? 1 : 0);
 209             memcpy(data, &isDeterminate, sizeof(isDeterminate));
 210             data += sizeof(jint);
 211 
 212             auto position = jfloat(renderProgress.position());
 213             memcpy(data, &position, sizeof(position));
 214             data += sizeof(jfloat);
 215 
 216             auto animationProgress = jfloat(renderProgress.animationProgress());
 217             memcpy(data, &animationProgress, sizeof(animationProgress));
 218             data += sizeof(jfloat);
 219 
 220             auto animationStartTime = jfloat(renderProgress.animationStartTime());
 221             memcpy(data, &animationStartTime, sizeof(animationStartTime));
 222         }
 223 #endif
 224 #if ENABLE(METER_ELEMENT)
 225     } else if (JNI_EXPAND(METER) == widgetIndex) {
 226         jfloat value = 0;
 227         jint region = 0;
 228         if (object.isMeter()) {
 229             HTMLMeterElement* meter = static_cast<HTMLMeterElement*>(object.node());
 230             value = meter->valueRatio();
 231             region = meter->gaugeRegion();
 232 #if ENABLE(PROGRESS_ELEMENT)
 233         } else if (is<RenderProgress>(object>)) {
 234             RenderProgress& renderProgress = downcast<RenderProgress>(object);
 235             value = jfloat(renderProgress.position());
 236 #endif
 237         }
 238 
 239         extParams.grow(sizeof(jfloat) + sizeof(jint));
 240         jbyte *data = extParams.data();
 241         memcpy(data, &value, sizeof(value));
 242         data += sizeof(jfloat);
 243 
 244         memcpy(data, &region, sizeof(region));
 245 #endif
 246     }
 247 
 248     static jmethodID mid = env->GetMethodID(getJRenderThemeClass(), "createWidget",
 249             "(JIIIIILjava/nio/ByteBuffer;)Lcom/sun/webkit/graphics/Ref;");
 250     ASSERT(mid);
 251 
 252     RefPtr<RQRef> widgetRef = RQRef::create(
 253         env->CallObjectMethod(jobject(*jRenderTheme), mid,
 254             ptr_to_jlong(&object),
 255             (jint)widgetIndex,
 256             (jint)state,
 257             (jint)rect.width(), (jint)rect.height(),
 258             (jint)bgColor,
 259             (jobject)JLObject(extParams.isEmpty()
 260                 ? nullptr
 261                 : env->NewDirectByteBuffer(
 262                     extParams.data(),
 263                     extParams.size())))
 264         );
 265     if (!widgetRef.get()) {
 266         //switch to WebKit default render
 267         return true;
 268     }
 269     CheckAndClearException(env);
 270 
 271     // widgetRef will go into rq's inner refs vector.
 272     paintInfo.context().platformContext()->rq().freeSpace(20)
 273     << (jint)com_sun_webkit_graphics_GraphicsDecoder_DRAWWIDGET
 274     << (jint)*jRenderTheme
 275     << widgetRef
 276     << (jint)rect.x() << (jint)rect.y();
 277 
 278     return false;
 279 }
 280 
 281 #if ENABLE(PROGRESS_ELEMENT)
 282 void RenderThemeJava::adjustProgressBarStyle(StyleResolver&, RenderStyle& style, const Element*) const
 283 {
 284     style.setBoxShadow(nullptr);
 285 }
 286 
 287 //utatodo: ask Java theme
 288 // These values have been copied from RenderThemeChromiumSkia.cpp
 289 static const int progressActivityBlocks = 5;
 290 static const int progressAnimationFrames = 10;
 291 static const double progressAnimationInterval = 0.125;
 292 double RenderThemeJava::animationRepeatIntervalForProgressBar(RenderProgress&) const
 293 {
 294     return progressAnimationInterval;
 295 }
 296 
 297 double RenderThemeJava::animationDurationForProgressBar(RenderProgress&) const
 298 {
 299     return progressAnimationInterval * progressAnimationFrames * 2; // "2" for back and forth;
 300 }
 301 
 302 bool RenderThemeJava::paintProgressBar(const RenderObject&o, const PaintInfo& i, const IntRect& rect)
 303 {
 304     return paintWidget(JNI_EXPAND(PROGRESS_BAR), o, i, rect);
 305 }
 306 #endif
 307 
 308 #if ENABLE(METER_ELEMENT)
 309 bool RenderThemeJava::supportsMeter(ControlPart part) const
 310 {
 311 #if ENABLE(PROGRESS_ELEMENT)
 312     if (part == ProgressBarPart) {
 313         return true;
 314     }
 315 #endif
 316     return (part == MeterPart);
 317 }
 318 
 319 bool RenderThemeJava::paintMeter(const RenderObject&o, const PaintInfo& i, const IntRect& rect)
 320 {
 321     return paintWidget(JNI_EXPAND(METER), o, i, rect);
 322 }
 323 #endif
 324 
 325 void RenderThemeJava::setCheckboxSize(RenderStyle& style) const
 326 {
 327     setRadioSize(style);
 328 }
 329 
 330 bool RenderThemeJava::paintCheckbox(const RenderObject&o, const PaintInfo& i, const IntRect& rect)
 331 {
 332     return paintWidget(JNI_EXPAND(CHECK_BOX), o, i, rect);
 333 }
 334 
 335 void RenderThemeJava::setRadioSize(RenderStyle& style) const
 336 {
 337     // If the width and height are both specified, then we have nothing to do.
 338     if ((!style.width().isIntrinsicOrAuto() && !style.height().isAuto())) {
 339         return;
 340     }
 341 
 342     JNIEnv* env = WebCore_GetJavaEnv();
 343 
 344     static jmethodID mid = env->GetMethodID(getJRenderThemeClass(), "getRadioButtonSize", "()I");
 345     ASSERT(mid);
 346 
 347     // Get from default theme object.
 348     int radioRadius = env->CallIntMethod((jobject)getJRenderTheme(nullptr), mid);
 349     CheckAndClearException(env);
 350 
 351     if (style.width().isIntrinsicOrAuto()) {
 352         style.setWidth(Length(radioRadius, Fixed));
 353     }
 354 
 355     if (style.height().isAuto()) {
 356         style.setHeight(Length(radioRadius, Fixed));
 357     }
 358 }
 359 
 360 bool RenderThemeJava::paintRadio(const RenderObject&o, const PaintInfo& i, const IntRect& rect)
 361 {
 362     return paintWidget(JNI_EXPAND(RADIO_BUTTON), o, i, rect);
 363 }
 364 
 365 bool RenderThemeJava::paintButton(const RenderObject&o, const PaintInfo& i, const IntRect& rect)
 366 {
 367     return paintWidget(JNI_EXPAND(BUTTON), o, i, rect);
 368 }
 369 
 370 void RenderThemeJava::adjustTextFieldStyle(StyleResolver&, RenderStyle&, const Element*) const
 371 {
 372     notImplemented();
 373 }
 374 
 375 bool RenderThemeJava::paintTextField(const RenderObject&o, const PaintInfo& i, const FloatRect& rect)
 376 {
 377     return paintWidget(JNI_EXPAND(TEXT_FIELD), o, i, rect);
 378 }
 379 
 380 void RenderThemeJava::adjustSearchFieldStyle(StyleResolver&, RenderStyle&, const Element*) const
 381 {
 382     notImplemented();
 383 }
 384 
 385 bool RenderThemeJava::paintSearchField(const RenderObject&o, const PaintInfo& i, const IntRect& rect)
 386 {
 387     return paintWidget(JNI_EXPAND(TEXT_FIELD), o, i, rect);
 388 }
 389 
 390 void RenderThemeJava::adjustTextAreaStyle(StyleResolver&, RenderStyle& style, const Element*) const
 391 {
 392     if (style.paddingTop().isIntrinsicOrAuto())
 393         style.setPaddingTop(Length(1, Fixed));
 394     if (style.paddingBottom().isIntrinsicOrAuto())
 395         style.setPaddingBottom(Length(1, Fixed));
 396 }
 397 
 398 bool RenderThemeJava::paintTextArea(const RenderObject&o, const PaintInfo& i, const FloatRect& r)
 399 {
 400     return paintTextField(o, i, r);
 401 }
 402 
 403 void RenderThemeJava::adjustButtonStyle(StyleResolver&, RenderStyle& style, const Element*) const
 404 {
 405     if (style.appearance() == PushButtonPart) {
 406         // Ignore line-height.
 407         style.setLineHeight(RenderStyle::initialLineHeight());
 408     }
 409 }
 410 
 411 enum JavaControlSize {
 412     JavaRegularControlSize, // The control is sized as regular.
 413     JavaSmallControlSize,   // The control has a smaller size.
 414     JavaMiniControlSize     // The control has a smaller size than JavaSmallControlSize.
 415 };
 416 
 417 static float systemFontSizeForControlSize(JavaControlSize controlSize)
 418 {
 419     static float sizes[] = { 16.0f, 13.0f, 10.0f };
 420 
 421     return sizes[controlSize];
 422 }
 423 
 424 void RenderThemeJava::updateCachedSystemFontDescription(CSSValueID propId, FontCascadeDescription& fontDescription) const
 425 {
 426     // This logic owes much to RenderThemeSafari.cpp.
 427     static FontCascadeDescription systemFont;
 428     static FontCascadeDescription smallSystemFont;
 429     static FontCascadeDescription menuFont;
 430     static FontCascadeDescription labelFont;
 431     static FontCascadeDescription miniControlFont;
 432     static FontCascadeDescription smallControlFont;
 433     static FontCascadeDescription controlFont;
 434 
 435     FontCascadeDescription* cachedDesc;
 436     float fontSize = 0;
 437     switch (propId) {
 438         case CSSValueSmallCaption:
 439             cachedDesc = &smallSystemFont;
 440             if (!smallSystemFont.isAbsoluteSize())
 441                 fontSize = systemFontSizeForControlSize(JavaSmallControlSize);
 442             break;
 443         case CSSValueMenu:
 444             cachedDesc = &menuFont;
 445             if (!menuFont.isAbsoluteSize())
 446                 fontSize = systemFontSizeForControlSize(JavaRegularControlSize);
 447             break;
 448         case CSSValueStatusBar:
 449             cachedDesc = &labelFont;
 450             if (!labelFont.isAbsoluteSize())
 451                 fontSize = 10.0f;
 452             break;
 453         case CSSValueWebkitMiniControl:
 454             cachedDesc = &miniControlFont;
 455             if (!miniControlFont.isAbsoluteSize())
 456                 fontSize = systemFontSizeForControlSize(JavaMiniControlSize);
 457             break;
 458         case CSSValueWebkitSmallControl:
 459             cachedDesc = &smallControlFont;
 460             if (!smallControlFont.isAbsoluteSize())
 461                 fontSize = systemFontSizeForControlSize(JavaSmallControlSize);
 462             break;
 463         case CSSValueWebkitControl:
 464             cachedDesc = &controlFont;
 465             if (!controlFont.isAbsoluteSize())
 466                 fontSize = systemFontSizeForControlSize(JavaRegularControlSize);
 467             break;
 468         default:
 469             cachedDesc = &systemFont;
 470             if (!systemFont.isAbsoluteSize())
 471                 fontSize = 13.0f;
 472     }
 473 
 474     if (fontSize) {
 475         cachedDesc->setIsAbsoluteSize(true);
 476         // cachedDesc->setGenericFamily(FontCascadeDescription::NoFamily);
 477         //cachedDesc->setOneFamily("Lucida Grande");
 478         cachedDesc->setOneFamily("Tahoma");
 479         cachedDesc->setSpecifiedSize(fontSize);
 480         cachedDesc->setWeight(normalWeightValue());
 481         cachedDesc->setItalic(normalItalicValue());
 482     }
 483     fontDescription = *cachedDesc;
 484 }
 485 
 486 void RenderThemeJava::adjustSliderTrackStyle(StyleResolver& selector, RenderStyle& style, const Element* element) const
 487 {
 488     //utatodo: we need to measure the control in Java theme.
 489     RenderTheme::adjustSliderTrackStyle(selector, style, element);
 490 }
 491 
 492 bool RenderThemeJava::paintSliderTrack(const RenderObject&object, const PaintInfo& info, const IntRect& rect)
 493 {
 494     return paintWidget(JNI_EXPAND(SLIDER), object, info, rect);
 495 }
 496 
 497 void getSliderThumbSize(jint sliderType, int *width, int *height)
 498 {
 499     JNIEnv* env = WebCore_GetJavaEnv();
 500     JGClass cls = JLClass(env->FindClass(RENDER_MEDIA_CONTROLS_CLASS_NAME));
 501     ASSERT(cls);
 502 
 503     jmethodID mid = env->GetStaticMethodID(cls, "fwkGetSliderThumbSize", "(I)I");
 504     ASSERT(mid);
 505 
 506     jint size = env->CallStaticIntMethod(cls, mid, sliderType);
 507     CheckAndClearException(env);
 508     *width = (size >> 16) & 0xFFFF;
 509     *height = size & 0xFFFF;
 510 }
 511 
 512 //utatodo: we need to measure the control in Java theme, do not make it const
 513 const int sliderThumbWidth = 17;
 514 const int sliderThumbHeight = 17;
 515 
 516 void RenderThemeJava::adjustSliderThumbSize(RenderStyle& style, const Element*) const
 517 {
 518     ControlPart part = style.appearance();
 519 #if ENABLE(VIDEO)
 520     if (part == SliderThumbVerticalPart || part == SliderThumbHorizontalPart)
 521 #endif
 522     {
 523         style.setWidth(Length(sliderThumbHeight, Fixed));
 524         style.setHeight(Length(sliderThumbWidth, Fixed));
 525     }
 526 #if ENABLE(VIDEO)
 527     else if (part == MediaSliderThumbPart) {
 528         static int timeWidth = 0;
 529         static int timeHeight;
 530         if (timeWidth == 0) {
 531             getSliderThumbSize(JNI_EXPAND_MEDIA(SLIDER_TYPE_TIME), &timeWidth, &timeHeight);
 532         }
 533         style.setWidth(Length(timeWidth, Fixed));
 534         style.setHeight(Length(timeHeight, Fixed));
 535     } else if (part == MediaVolumeSliderThumbPart) {
 536         static int volumeWidth = 0;
 537         static int volumeHeight;
 538         if (volumeWidth == 0) {
 539             getSliderThumbSize(JNI_EXPAND_MEDIA(SLIDER_TYPE_VOLUME), &volumeWidth, &volumeHeight);
 540         }
 541         style.setWidth(Length(volumeWidth, Fixed));
 542         style.setHeight(Length(volumeHeight, Fixed));
 543     }
 544 #endif
 545 }
 546 
 547 bool RenderThemeJava::paintSliderThumb(const RenderObject&, const PaintInfo&, const IntRect&)
 548 {
 549     // We've already painted it in paintSliderTrack(), no need to do anything here.
 550     return false;
 551 }
 552 
 553 void RenderThemeJava::adjustMenuListStyle(StyleResolver&, RenderStyle& style, const Element*) const
 554 {
 555     // Add in the padding that we'd like to use.
 556     style.setPaddingRight(Length(20.0f + style.paddingRight().value(), Fixed));
 557     style.setPaddingLeft(Length(2.0f + style.paddingLeft().value(), Fixed));
 558 }
 559 
 560 bool RenderThemeJava::paintMenuList(const RenderObject& o, const PaintInfo& i, const FloatRect& rect)
 561 {
 562     return paintWidget(JNI_EXPAND(MENU_LIST), o, i, rect);
 563 }
 564 
 565 void RenderThemeJava::adjustMenuListButtonStyle(StyleResolver& selector, RenderStyle& style, const Element* e) const
 566 {
 567     style.resetBorderRadius();
 568     adjustMenuListStyle(selector, style, e);
 569 }
 570 
 571 bool RenderThemeJava::paintMenuListButtonDecorations(const RenderBox& o, const PaintInfo& i, const FloatRect& r)
 572 {
 573     IntRect rect(r.x() + r.width(), r.y(), r.height(), r.height());
 574 
 575     return paintWidget(JNI_EXPAND(MENU_LIST_BUTTON), o, i, rect);
 576 }
 577 
 578 bool RenderThemeJava::supportsFocusRing(const RenderStyle& style) const
 579 {
 580     if (!style.hasAppearance())
 581         return false;
 582 
 583     switch (style.appearance()) {
 584     case TextFieldPart:
 585     case TextAreaPart:
 586     case ButtonPart:
 587     case CheckboxPart:
 588     case RadioPart:
 589     case MenulistPart:
 590         return true;
 591     default:
 592         return RenderTheme::supportsFocusRing(style);
 593     }
 594 }
 595 
 596 Color RenderThemeJava::getSelectionColor(int index) const
 597 {
 598     JNIEnv* env = WebCore_GetJavaEnv();
 599     ASSERT(env);
 600 
 601     static jmethodID mid = env->GetMethodID(getJRenderThemeClass(), "getSelectionColor", "(I)I");
 602     ASSERT(mid);
 603 
 604     // Get from default theme object.
 605     jint c = env->CallIntMethod((jobject)getJRenderTheme(nullptr), mid, index);
 606     CheckAndClearException(env);
 607 
 608     return Color(c);
 609 }
 610 
 611 Color RenderThemeJava::platformActiveSelectionBackgroundColor() const
 612 {
 613     return getSelectionColor(JNI_EXPAND(BACKGROUND));
 614 }
 615 
 616 Color RenderThemeJava::platformInactiveSelectionBackgroundColor() const
 617 {
 618     return platformActiveSelectionBackgroundColor();
 619 }
 620 
 621 Color RenderThemeJava::platformActiveSelectionForegroundColor() const
 622 {
 623     return getSelectionColor(JNI_EXPAND(FOREGROUND));
 624 }
 625 
 626 Color RenderThemeJava::platformInactiveSelectionForegroundColor() const
 627 {
 628     return platformActiveSelectionForegroundColor();
 629 }
 630 
 631 #if ENABLE(VIDEO)
 632 String RenderThemeJava::mediaControlsScript()
 633 {
 634     StringBuilder scriptBuilder;
 635     scriptBuilder.append(mediaControlsLocalizedStringsJavaScript, sizeof(mediaControlsLocalizedStringsJavaScript));
 636     scriptBuilder.append(mediaControlsBaseJavaScript, sizeof(mediaControlsBaseJavaScript));
 637     scriptBuilder.append(mediaControlsGtkJavaScript, sizeof(mediaControlsGtkJavaScript));
 638     return scriptBuilder.toString();
 639 }
 640 
 641 String RenderThemeJava::extraMediaControlsStyleSheet()
 642 {
 643     return String(mediaControlsGtkUserAgentStyleSheet, sizeof(mediaControlsGtkUserAgentStyleSheet));
 644 }
 645 
 646 String RenderThemeJava::formatMediaControlsCurrentTime(float, float) const
 647 {
 648     return "";
 649 }
 650 
 651 String RenderThemeJava::formatMediaControlsRemainingTime(float currentTime, float duration) const
 652 {
 653     return formatMediaControlsTime(currentTime) + "/" + formatMediaControlsTime(duration);
 654 }
 655 
 656 /*
 657 bool RenderThemeJava::paintMediaFullscreenButton(const RenderObject& o, const PaintInfo& paintInfo, const IntRect &r);
 658 */
 659 
 660 bool RenderThemeJava::paintMediaPlayButton(const RenderObject& o, const PaintInfo& paintInfo, const IntRect& r)
 661 {
 662     auto mediaElement = parentMediaElement(o);
 663     if (mediaElement == nullptr)
 664         return false;
 665 
 666     // readyState can be NETWORK_EMPTY if preload is NONE
 667     jint type = mediaElement->readyState() == HTMLMediaElementEnums::ReadyState::HAVE_NOTHING
 668                     ? JNI_EXPAND_MEDIA(DISABLED_PLAY_BUTTON)
 669                     : mediaElement->paused()
 670                         ? JNI_EXPAND_MEDIA(PLAY_BUTTON)
 671                         : JNI_EXPAND_MEDIA(PAUSE_BUTTON);
 672     return paintMediaControl(type, o, paintInfo, r);
 673 }
 674 
 675 bool RenderThemeJava::paintMediaMuteButton(const RenderObject&o, const PaintInfo& paintInfo, const IntRect& r)
 676 {
 677     auto mediaElement = parentMediaElement(o);
 678     if (mediaElement == nullptr)
 679         return false;
 680 
 681     jint type = !mediaElement->hasAudio()
 682                     ? JNI_EXPAND_MEDIA(DISABLED_MUTE_BUTTON)
 683                     : mediaElement->muted()
 684                         ? JNI_EXPAND_MEDIA(UNMUTE_BUTTON)
 685                         : JNI_EXPAND_MEDIA(MUTE_BUTTON);
 686     return paintMediaControl(type, o, paintInfo, r);
 687 }
 688 
 689 /*
 690 bool RenderThemeJava::paintMediaSeekBackButton(const RenderObject& o, const PaintInfo& paintInfo, const IntRect &r);
 691 bool RenderThemeJava::paintMediaSeekForwardButton(const RenderObject& o, const PaintInfo& paintInfo, const IntRect &r);
 692 */
 693 
 694 bool RenderThemeJava::paintMediaSliderTrack(const RenderObject&o, const PaintInfo& paintInfo, const IntRect& r)
 695 {
 696     auto mediaElement = parentMediaElement(o);
 697     if (mediaElement == nullptr)
 698         return false;
 699 
 700     Ref<TimeRanges> timeRanges = mediaElement->buffered();
 701 
 702     paintInfo.context().platformContext()->rq().freeSpace(4
 703         + 4                 // number of timeRange pairs
 704         + timeRanges->length() * 4 *2   // timeRange pairs
 705         + 4 + 4             // duration and currentTime
 706         + 4 + 4 + 4 + 4     // x, y, w, h
 707         )
 708     << (jint)com_sun_webkit_graphics_GraphicsDecoder_RENDERMEDIA_TIMETRACK
 709     << (jint)timeRanges->length();
 710 
 711     //utatodo: need [double] support
 712     for (unsigned i = 0; i < timeRanges->length(); i++) {
 713         paintInfo.context().platformContext()->rq()
 714         << (jfloat)timeRanges->start(i).releaseReturnValue() << (jfloat)timeRanges->end(i).releaseReturnValue();
 715     }
 716 
 717     paintInfo.context().platformContext()->rq()
 718     << (jfloat)mediaElement->duration()
 719     << (jfloat)mediaElement->currentTime()
 720     << (jint)r.x() <<  (jint)r.y() << (jint)r.width() << (jint)r.height();
 721     return true;
 722 }
 723 
 724 bool RenderThemeJava::paintMediaSliderThumb(const RenderObject& o, const PaintInfo& paintInfo, const IntRect& r)
 725 {
 726     return paintMediaControl(JNI_EXPAND_MEDIA(TIME_SLIDER_THUMB), o, paintInfo, r);
 727 }
 728 
 729 bool RenderThemeJava::paintMediaVolumeSliderContainer(const RenderObject& o, const PaintInfo& paintInfo, const IntRect& r)
 730 {
 731     return paintMediaControl(JNI_EXPAND_MEDIA(VOLUME_CONTAINER), o, paintInfo, r);
 732 }
 733 
 734 bool RenderThemeJava::paintMediaVolumeSliderTrack(const RenderObject& o, const PaintInfo& paintInfo, const IntRect& r)
 735 {
 736     auto mediaElement = parentMediaElement(o);
 737     if (mediaElement == nullptr)
 738         return false;
 739 
 740     paintInfo.context().platformContext()->rq().freeSpace(28)
 741     << (jint)com_sun_webkit_graphics_GraphicsDecoder_RENDERMEDIA_VOLUMETRACK
 742     << (jfloat)mediaElement->volume()
 743     << (jint)(mediaElement->hasAudio() && !mediaElement->muted() ? 0 : 1)   // muted
 744     << (jint)r.x() <<  (jint)r.y() << (jint)r.width() << (jint)r.height();
 745     return true;
 746 
 747 }
 748 
 749 bool RenderThemeJava::paintMediaVolumeSliderThumb(const RenderObject& object, const PaintInfo& paintInfo, const IntRect& rect)
 750 {
 751     return paintMediaControl(JNI_EXPAND_MEDIA(VOLUME_THUMB), object, paintInfo, rect);
 752 }
 753 
 754 /*
 755 bool RenderThemeJava::paintMediaRewindButton(const RenderObject& o, const PaintInfo& paintInfo, const IntRect &r);
 756 bool RenderThemeJava::paintMediaReturnToRealtimeButton(const RenderObject& o, const PaintInfo& paintInfo, const IntRect &r);
 757 bool RenderThemeJava::paintMediaToggleClosedCaptionsButton(const RenderObject& o, const PaintInfo& paintInfo, const IntRect &r);
 758 */
 759 
 760 bool RenderThemeJava::paintMediaControlsBackground(const RenderObject&, const PaintInfo&, const IntRect&)
 761 {
 762 //    return paintMediaControl(JNI_EXPAND_MEDIA(BACKGROUND), o, paintInfo, r);
 763     return true;
 764 }
 765 
 766 bool RenderThemeJava::paintMediaCurrentTime(const RenderObject&, const PaintInfo&, const IntRect&)
 767 {
 768 //    return paintMediaControl(JNI_EXPAND_MEDIA(CURRENT_TIME), o, paintInfo, r);
 769     return true;
 770 }
 771 
 772 bool RenderThemeJava::paintMediaTimeRemaining(const RenderObject&, const PaintInfo&, const IntRect&)
 773 {
 774 //    return paintMediaControl(JNI_EXPAND_MEDIA(REMAINING_TIME), o, paintInfo, r);
 775     return true;
 776 }
 777 
 778 bool RenderThemeJava::paintMediaControl(jint type, const RenderObject&, const PaintInfo& paintInfo, const IntRect& r)
 779 {
 780     paintInfo.context().platformContext()->rq().freeSpace(24)
 781     << (jint)com_sun_webkit_graphics_GraphicsDecoder_RENDERMEDIACONTROL
 782     << type << (jint)r.x() <<  (jint)r.y()
 783     << (jint)r.width() << (jint)r.height();
 784 
 785     return true;
 786 }
 787 
 788 
 789 #undef JNI_EXPAND_MEDIA
 790 
 791 #endif  // ENABLE(VIDEO)
 792 
 793 }
 794 
 795 #undef JNI_EXPAND
 796