bool MediaControlsPainter::paintMediaOverlayPlayButton(const LayoutObject& object, const PaintInfo& paintInfo, const IntRect& rect)
{
    const HTMLMediaElement* mediaElement = toParentMediaElement(object);
    if (!mediaElement)
        return false;

    if (!hasSource(mediaElement) || !mediaElement->paused())
        return false;

    static Image* mediaOverlayPlay = platformResource("mediaplayerOverlayPlay",
        "mediaplayerOverlayPlayNew");

    IntRect buttonRect(rect);
    if (RuntimeEnabledFeatures::newMediaPlaybackUiEnabled()) {
        // Overlay play button covers the entire player, so center and draw a
        // smaller button.  Center in the entire element.
        const LayoutBox* box = mediaElement->layoutObject()->enclosingBox();
        if (!box)
            return false;
        int mediaHeight = box->pixelSnappedHeight();
        buttonRect.setX(rect.center().x() - mediaOverlayPlayButtonWidthNew / 2);
        buttonRect.setY(rect.center().y() - mediaOverlayPlayButtonHeightNew / 2
            + (mediaHeight - rect.height()) / 2);
        buttonRect.setWidth(mediaOverlayPlayButtonWidthNew);
        buttonRect.setHeight(mediaOverlayPlayButtonHeightNew);
    }

    return paintMediaButton(paintInfo.context, buttonRect, mediaOverlayPlay);
}
void findGoodTouchTargets(const IntRect& touchBox, LocalFrame* mainFrame, Vector<IntRect>& goodTargets, WillBeHeapVector<RawPtrWillBeMember<Node> >& highlightNodes)
{
    goodTargets.clear();

    int touchPointPadding = ceil(std::max(touchBox.width(), touchBox.height()) * 0.5);

    IntPoint touchPoint = touchBox.center();
    IntPoint contentsPoint = mainFrame->view()->windowToContents(touchPoint);

    HitTestResult result = mainFrame->eventHandler().hitTestResultAtPoint(contentsPoint, HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::ConfusingAndOftenMisusedDisallowShadowContent, IntSize(touchPointPadding, touchPointPadding));
    const WillBeHeapListHashSet<RefPtrWillBeMember<Node> >& hitResults = result.rectBasedTestResult();

    // Blacklist nodes that are container of disambiguated nodes.
    // It is not uncommon to have a clickable <div> that contains other clickable objects.
    // This heuristic avoids excessive disambiguation in that case.
    WillBeHeapHashSet<RawPtrWillBeMember<Node> > blackList;
    for (WillBeHeapListHashSet<RefPtrWillBeMember<Node> >::const_iterator it = hitResults.begin(); it != hitResults.end(); ++it) {
        // Ignore any Nodes that can't be clicked on.
        RenderObject* renderer = it->get()->renderer();
        if (!renderer || !it->get()->willRespondToMouseClickEvents())
            continue;

        // Blacklist all of the Node's containers.
        for (RenderBlock* container = renderer->containingBlock(); container; container = container->containingBlock()) {
            Node* containerNode = container->node();
            if (!containerNode)
                continue;
            if (!blackList.add(containerNode).isNewEntry)
                break;
        }
    }

    WillBeHeapHashMap<RawPtrWillBeMember<Node>, TouchTargetData> touchTargets;
    float bestScore = 0;
    for (WillBeHeapListHashSet<RefPtrWillBeMember<Node> >::const_iterator it = hitResults.begin(); it != hitResults.end(); ++it) {
        for (Node* node = it->get(); node; node = node->parentNode()) {
            if (blackList.contains(node))
                continue;
            if (node->isDocumentNode() || isHTMLHtmlElement(*node) || isHTMLBodyElement(*node))
                break;
            if (node->willRespondToMouseClickEvents()) {
                TouchTargetData& targetData = touchTargets.add(node, TouchTargetData()).storedValue->value;
                targetData.windowBoundingBox = boundingBoxForEventNodes(node);
                targetData.score = scoreTouchTarget(touchPoint, touchPointPadding, targetData.windowBoundingBox);
                bestScore = std::max(bestScore, targetData.score);
                break;
            }
        }
    }

    for (WillBeHeapHashMap<RawPtrWillBeMember<Node>, TouchTargetData>::iterator it = touchTargets.begin(); it != touchTargets.end(); ++it) {
        // Currently the scoring function uses the overlap area with the fat point as the score.
        // We ignore the candidates that has less than 1/2 overlap (we consider not really ambiguous enough) than the best candidate to avoid excessive popups.
        if (it->value.score < bestScore * 0.5)
            continue;
        goodTargets.append(it->value.windowBoundingBox);
        highlightNodes.append(it->key);
    }
}
Esempio n. 3
0
bool snapTo(const SubtargetGeometry& geom, const IntPoint& touchPoint, const IntRect& touchArea, IntPoint& adjustedPoint)
{
    FrameView* view = geom.node()->document()->view();
    FloatQuad quad = geom.quad();

    if (quad.isRectilinear()) {
        IntRect contentBounds = geom.boundingBox();
        // Convert from frame coordinates to window coordinates.
        IntRect bounds = view->contentsToWindow(contentBounds);
        if (bounds.contains(touchPoint)) {
            adjustedPoint = touchPoint;
            return true;
        }
        if (bounds.intersects(touchArea)) {
            bounds.intersect(touchArea);
            adjustedPoint = bounds.center();
            return true;
        }
        return false;
    }

    // The following code tries to adjust the point to place inside a both the touchArea and the non-rectilinear quad.
    // FIXME: This will return the point inside the touch area that is the closest to the quad center, but does not
    // guarantee that the point will be inside the quad. Corner-cases exist where the quad will intersect but this
    // will fail to adjust the point to somewhere in the intersection.

    // Convert quad from content to window coordinates.
    FloatPoint p1 = contentsToWindow(view, quad.p1());
    FloatPoint p2 = contentsToWindow(view, quad.p2());
    FloatPoint p3 = contentsToWindow(view, quad.p3());
    FloatPoint p4 = contentsToWindow(view, quad.p4());
    quad = FloatQuad(p1, p2, p3, p4);

    if (quad.containsPoint(touchPoint)) {
        adjustedPoint = touchPoint;
        return true;
    }

    // Pull point towards the center of the element.
    FloatPoint center = quad.center();

    adjustPointToRect(center, touchArea);
    adjustedPoint = roundedIntPoint(center);

    return quad.containsPoint(adjustedPoint);
}
Esempio n. 4
0
static bool isRectInDirection(FocusDirection direction, const IntRect& curRect, const IntRect& targetRect)
{
    IntPoint center(targetRect.center());
    int targetMiddle = isHorizontalMove(direction) ? center.x() : center.y();

    switch (direction) {
    case FocusDirectionLeft:
        return targetMiddle < curRect.x();
    case FocusDirectionRight:
        return targetMiddle > curRect.right();
    case FocusDirectionUp:
        return targetMiddle < curRect.y();
    case FocusDirectionDown:
        return targetMiddle > curRect.bottom();
    default:
        ASSERT_NOT_REACHED();
    }

    return false;
}
HRESULT AccessibleText::scrollSubstringTo(long startIndex, long endIndex, enum IA2ScrollType scrollType)
{
    if (initialCheck() == E_POINTER)
        return E_POINTER;

    startIndex = convertSpecialOffset(startIndex);
    endIndex = convertSpecialOffset(endIndex);

    VisiblePositionRange textRange = m_object->visiblePositionRangeForRange(PlainTextRange(startIndex, endIndex-startIndex));
    if (textRange.start.isNull() || textRange.end.isNull())
        return S_FALSE;

    IntRect boundingBox = makeRange(textRange.start, textRange.end)->absoluteBoundingBox();
    switch (scrollType) {
    case IA2_SCROLL_TYPE_TOP_LEFT:
        m_object->scrollToGlobalPoint(boundingBox.minXMinYCorner());
        break;
    case IA2_SCROLL_TYPE_BOTTOM_RIGHT:
        m_object->scrollToGlobalPoint(boundingBox.maxXMaxYCorner());
        break;
    case IA2_SCROLL_TYPE_TOP_EDGE:
        m_object->scrollToGlobalPoint(IntPoint((boundingBox.x() + boundingBox.maxX()) / 2, boundingBox.y()));
        break;
    case IA2_SCROLL_TYPE_BOTTOM_EDGE:
        m_object->scrollToGlobalPoint(IntPoint((boundingBox.x() + boundingBox.maxX()) / 2, boundingBox.maxY()));
        break;
    case IA2_SCROLL_TYPE_LEFT_EDGE:
        m_object->scrollToGlobalPoint(IntPoint(boundingBox.x(), (boundingBox.y() + boundingBox.maxY()) / 2));
        break;
    case IA2_SCROLL_TYPE_RIGHT_EDGE:
        m_object->scrollToGlobalPoint(IntPoint(boundingBox.maxX(), (boundingBox.y() + boundingBox.maxY()) / 2));
        break;
    case IA2_SCROLL_TYPE_ANYWHERE:
        m_object->scrollToGlobalPoint(boundingBox.center());
        break;
    default:
        return E_INVALIDARG;
    }
    return S_OK;
}
void MediaControlsPainter::adjustMediaSliderThumbPaintSize(const IntRect& rect, const ComputedStyle& style, IntRect& rectOut)
{
    // Adjust the rectangle to be centered, the right size for the image.
    // We do this because it's quite hard to get the thumb touch target
    // to match.  So, we provide the touch target size with
    // adjustMediaSliderThumbSize(), and scale it back when we paint.
    rectOut = rect;

    if (!RuntimeEnabledFeatures::newMediaPlaybackUiEnabled()) {
        // ...except for the old UI.
        return;
    }

    float zoomLevel = style.effectiveZoom();
    float zoomedPaintWidth = mediaSliderThumbPaintWidthNew * zoomLevel;
    float zoomedPaintHeight = mediaSliderThumbPaintHeightNew * zoomLevel;

    rectOut.setX(rect.center().x() - zoomedPaintWidth / 2);
    rectOut.setY(rect.center().y() - zoomedPaintHeight / 2);
    rectOut.setWidth(zoomedPaintWidth);
    rectOut.setHeight(zoomedPaintHeight);
}
Esempio n. 7
0
static inline int middle(FocusDirection direction, const IntRect& rect)
{
    IntPoint center(rect.center());
    return isHorizontalMove(direction) ? center.y(): center.x();
}
Esempio n. 8
0
void WKViewFindZoomableAreaForRect(WKViewRef viewRef, WKRect wkRect)
{
    IntRect rect = toIntRect(wkRect);
    toImpl(viewRef)->findZoomableAreaForPoint(rect.center(), rect.size());
}
void RenderSkinMediaButton::Draw(SkCanvas* canvas, const IntRect& r,
                                 MediaButton buttonType, bool translucent,
                                 bool drawBackground, const IntRect& thumb)//4.2 Merge
{
    if (!gDecoded) {
        Decode();
    }

    if (!canvas)
        return;

    // If we failed to decode, do nothing.  This way the browser still works,
    // and webkit will still draw the label and layout space for us.
    if (gDecodingFailed)
        return;

    bool drawsNinePatch = false;
    bool drawsImage = true;

    int ninePatchIndex = 0;
    int imageIndex = 0;

    SkRect bounds(r);
    SkScalar imageMargin = 8;
    SkPaint paint;

    int alpha = 255;
    if (translucent)
        alpha = 190;

    SkColor backgroundColor = SkColorSetARGB(alpha, 34, 34, 34);
    SkColor trackBackgroundColor = SkColorSetARGB(255, 100, 100, 100);
    paint.setColor(backgroundColor);
//Android KITKAT Merge  - START
//    paint.setFlags(SkPaint::kFilterBitmap_Flag);
    //P140210-04273 : 
    // In D2 Device if we pass kMedium_FilterLevel image gets corrupted while drawing the image into the canvas. So loading icons was corrupting
    // kLow_FilterLevel works for other kitkat devices.
    //WAS paint.setFilterLevel(SkPaint::kMedium_FilterLevel);
    paint.setFilterLevel(SkPaint::kLow_FilterLevel);	
//Android KITKAT Merge  - END


    switch (buttonType) {
    case PAUSE:
    case PLAY:
    case MUTE:
    case REWIND:
    case FORWARD:
    case FULLSCREEN:
    {
         imageIndex = buttonType + 1;
         paint.setColor(backgroundColor);
         break;
    }
    case SPINNER_OUTER:
    case SPINNER_INNER:
    case VIDEO:
    {
         imageIndex = buttonType + 1;
         break;
    }
    case BACKGROUND_SLIDER:
    {
         drawsImage = false;
         break;
    }
    case SLIDER_TRACK:
    {
         drawsNinePatch = true;
         drawsImage = false;
         ninePatchIndex = buttonType + 1;
         break;
    }
    case SLIDER_THUMB:
    {
         imageMargin = 0;
         imageIndex = buttonType + 1;
         break;
    }
    default:
         return;
    }

    if (drawBackground) {
        canvas->drawRect(r, paint);
    }

    if (drawsNinePatch) {
        const PatchData& pd = gFiles[ninePatchIndex];
        int marginValue = pd.margin + pd.outset;

        SkIRect margin;
        margin.set(marginValue, marginValue, marginValue, marginValue);
        if (buttonType == SLIDER_TRACK) {
            // Cut the height in half (with some extra slop determined by trial
            // and error to get the placement just right.
            SkScalar quarterHeight = SkScalarHalf(SkScalarHalf(bounds.height()));
            bounds.fTop += quarterHeight + SkScalarHalf(3);
            bounds.fBottom += -quarterHeight + SK_ScalarHalf;
            if (!thumb.isEmpty()) {//4.2 Merge
                // Inset the track by half the width of the thumb, so the track
                // does not appear to go beyond the space where the thumb can
                // be.
                SkScalar thumbHalfWidth = SkIntToScalar(thumb.width()/2);
                bounds.fLeft += thumbHalfWidth;
                bounds.fRight -= thumbHalfWidth;
                if (thumb.x() > 0) {
                    // The video is past the starting point.  Show the area to
                    // left of the thumb as having been played.
                    SkScalar alreadyPlayed = SkIntToScalar(thumb.center().x() + r.x());
                    SkRect playedRect(bounds);
                    playedRect.fRight = alreadyPlayed;
                    SkNinePatch::DrawNine(canvas, playedRect, gButton[0], margin);
                    bounds.fLeft = alreadyPlayed;
                }

            }
        }
        SkNinePatch::DrawNine(canvas, bounds, gButton[ninePatchIndex], margin);
    }

    if (drawsImage) {
        SkScalar SIZE = gButton[imageIndex].width();
        SkScalar width = r.width();
        SkScalar scale = SkScalarDiv(width - 2*imageMargin, SIZE);
        int saveScaleCount = canvas->save();
        canvas->translate(bounds.fLeft + imageMargin, bounds.fTop + imageMargin);
        canvas->scale(scale, scale);
        canvas->drawBitmap(gButton[imageIndex], 0, 0, &paint);
        canvas->restoreToCount(saveScaleCount);
    }
}
Esempio n. 10
0
void TouchActionTest::runTestOnTree(ContainerNode* root,
                                    WebView* webView,
                                    TouchActionTrackingWebViewClient& client) {
  // Find all elements to test the touch-action of in the document.
  TrackExceptionState es;

  // Oilpan: see runTouchActionTest() comment why these are persistent
  // references.
  Persistent<StaticElementList> elements =
      root->querySelectorAll("[expected-action]", es);
  ASSERT_FALSE(es.hadException());

  for (unsigned index = 0; index < elements->length(); index++) {
    Element* element = elements->item(index);
    element->scrollIntoViewIfNeeded();

    std::string failureContext("Test case: ");
    if (element->hasID()) {
      failureContext.append(element->getIdAttribute().ascii().data());
    } else if (element->firstChild()) {
      failureContext.append("\"");
      failureContext.append(element->firstChild()
                                ->textContent(false)
                                .stripWhiteSpace()
                                .ascii()
                                .data());
      failureContext.append("\"");
    } else {
      failureContext += "<missing ID>";
    }

    // Run each test three times at different positions in the element.
    // Note that we don't want the bounding box because our tests sometimes have
    // elements with multiple border boxes with other elements in between. Use
    // the first border box (which we can easily visualize in a browser for
    // debugging).
    Persistent<ClientRectList> rects = element->getClientRects();
    ASSERT_GE(rects->length(), 0u) << failureContext;
    Persistent<ClientRect> r = rects->item(0);
    FloatRect clientFloatRect =
        FloatRect(r->left(), r->top(), r->width(), r->height());
    IntRect clientRect = enclosedIntRect(clientFloatRect);
    for (int locIdx = 0; locIdx < 3; locIdx++) {
      IntPoint framePoint;
      std::stringstream contextStream;
      contextStream << failureContext << " (";
      switch (locIdx) {
        case 0:
          framePoint = clientRect.center();
          contextStream << "center";
          break;
        case 1:
          framePoint = clientRect.location();
          contextStream << "top-left";
          break;
        case 2:
          framePoint = clientRect.maxXMaxYCorner();
          framePoint.move(-1, -1);
          contextStream << "bottom-right";
          break;
        default:
          FAIL() << "Invalid location index.";
      }

      IntPoint windowPoint =
          root->document().frame()->view()->convertToRootFrame(framePoint);
      contextStream << "=" << windowPoint.x() << "," << windowPoint.y() << ").";
      std::string failureContextPos = contextStream.str();

      LocalFrame* mainFrame =
          static_cast<LocalFrame*>(webView->mainFrame()->toImplBase()->frame());
      FrameView* mainFrameView = mainFrame->view();
      IntRect visibleRect = windowClipRect(*mainFrameView);
      ASSERT_TRUE(visibleRect.contains(windowPoint))
          << failureContextPos
          << " Test point not contained in visible area: " << visibleRect.x()
          << "," << visibleRect.y() << "-" << visibleRect.maxX() << ","
          << visibleRect.maxY();

      // First validate that a hit test at this point will really hit the
      // element we intended. This is the easiest way for a test to be broken,
      // but has nothing really to do with touch action.  Note that we can't use
      // WebView's hit test API because it doesn't look into shadow DOM.
      IntPoint docPoint(mainFrameView->frameToContents(windowPoint));
      HitTestResult result = mainFrame->eventHandler().hitTestResultAtPoint(
          docPoint, HitTestRequest::ReadOnly | HitTestRequest::Active);
      ASSERT_EQ(element, result.innerElement())
          << "Unexpected hit test result " << failureContextPos
          << "  Got element: \""
          << result.innerElement()
                 ->outerHTML()
                 .stripWhiteSpace()
                 .left(80)
                 .ascii()
                 .data()
          << "\"" << std::endl
          << "Document render tree:" << std::endl
          << externalRepresentation(root->document().frame()).utf8().data();

      // Now send the touch event and check any touch action result.
      sendTouchEvent(webView, WebInputEvent::TouchStart, windowPoint);

      AtomicString expectedAction = element->getAttribute("expected-action");
      if (expectedAction == "auto") {
        // Auto is the default - no action set.
        EXPECT_EQ(0, client.touchActionSetCount()) << failureContextPos;
        EXPECT_EQ(WebTouchActionAuto, client.lastTouchAction())
            << failureContextPos;
      } else {
        // Should have received exactly one touch action.
        EXPECT_EQ(1, client.touchActionSetCount()) << failureContextPos;
        if (client.touchActionSetCount()) {
          if (expectedAction == "none") {
            EXPECT_EQ(WebTouchActionNone, client.lastTouchAction())
                << failureContextPos;
          } else if (expectedAction == "pan-x") {
            EXPECT_EQ(WebTouchActionPanX, client.lastTouchAction())
                << failureContextPos;
          } else if (expectedAction == "pan-y") {
            EXPECT_EQ(WebTouchActionPanY, client.lastTouchAction())
                << failureContextPos;
          } else if (expectedAction == "pan-x-y") {
            EXPECT_EQ((WebTouchActionPan), client.lastTouchAction())
                << failureContextPos;
          } else if (expectedAction == "manipulation") {
            EXPECT_EQ((WebTouchActionManipulation), client.lastTouchAction())
                << failureContextPos;
          } else {
            FAIL() << "Unrecognized expected-action \""
                   << expectedAction.ascii().data() << "\" "
                   << failureContextPos;
          }
        }
      }

      // Reset webview touch state.
      client.reset();
      sendTouchEvent(webView, WebInputEvent::TouchCancel, windowPoint);
      EXPECT_EQ(0, client.touchActionSetCount());
    }
  }
}