1 /*
   2  * Copyright (c) 2011, 2014, 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 package com.sun.javafx.webkit;
  27 
  28 import java.lang.ref.WeakReference;
  29 import java.util.ArrayList;
  30 import java.util.List;
  31 
  32 import com.sun.javafx.scene.input.ExtendedInputMethodRequests;
  33 import javafx.geometry.Point2D;
  34 import javafx.scene.input.InputMethodEvent;
  35 import javafx.scene.input.InputMethodHighlight;
  36 import javafx.scene.input.InputMethodRequests;
  37 import javafx.scene.input.InputMethodTextRun;
  38 import javafx.scene.web.WebView;
  39 
  40 import com.sun.webkit.InputMethodClient;
  41 import com.sun.webkit.WebPage;
  42 import com.sun.webkit.event.WCInputMethodEvent;
  43 import com.sun.webkit.graphics.WCPoint;
  44 
  45 public final class InputMethodClientImpl
  46     implements InputMethodClient, ExtendedInputMethodRequests
  47 {
  48     private final WeakReference<WebView> wvRef;
  49     private final WebPage webPage;
  50 
  51     // the state of the last setInputMethodState() call.
  52     private boolean state;
  53 
  54     public InputMethodClientImpl(WebView wv, WebPage webPage) {
  55         this.wvRef = new WeakReference<WebView>(wv);
  56         this.webPage = webPage;
  57         if (webPage != null) {
  58             webPage.setInputMethodClient(this);
  59         }
  60     }
  61 
  62     public void activateInputMethods(final boolean doActivate) {
  63         WebView wv = wvRef.get();
  64         if (wv != null && wv.getScene() != null) {
  65             wv.getScene().impl_enableInputMethodEvents(doActivate);
  66         }
  67         state = doActivate;
  68     }
  69 
  70     public boolean getInputMethodState() {
  71         return state;
  72     }
  73 
  74     /**
  75      * Converts the given InputMethodEvent to a WCInputMethodEvent.
  76      */
  77     public static WCInputMethodEvent convertToWCInputMethodEvent(InputMethodEvent ie) {
  78         List<Integer> underlines = new ArrayList<Integer>();
  79         StringBuilder composed = new StringBuilder();
  80         int pos = 0;
  81 
  82         // Scan the given composedText to find input method highlight attribute runs.
  83         for (InputMethodTextRun run : ie.getComposed()) {
  84             String rawText = run.getText();
  85 
  86             // Convert highlight information of the attribute run into a
  87             // CompositionUnderline.
  88             InputMethodHighlight imh = run.getHighlight();
  89             underlines.add(pos);
  90             underlines.add(pos + rawText.length());
  91             // WebKit CompostionUnderline supports only two kinds of highlighting
  92             // attributes, thin and thick underlines. The SELECTED_CONVERTED
  93             // and SELECTED_RAW attributes of JavaFX are mapped to the thick one.
  94             underlines.add((imh == InputMethodHighlight.SELECTED_CONVERTED ||
  95                             imh == InputMethodHighlight.SELECTED_RAW) ? 1 : 0);
  96             pos += rawText.length();
  97             composed.append(rawText);
  98         }
  99 
 100         int size = underlines.size();
 101         // In case there's no highlight information, create an underline element
 102         // for the entire text
 103         if (size == 0) {
 104             underlines.add(0);
 105             underlines.add(pos);
 106             underlines.add(0); // thin underline
 107             size = underlines.size();
 108         }
 109         int[] attributes = new int[size];
 110         for (int i = 0; i < size; i++) {
 111             attributes[i] = underlines.get(i);
 112         }
 113 
 114         return new WCInputMethodEvent(ie.getCommitted(), composed.toString(),
 115                 attributes, ie.getCaretPosition());
 116     }
 117 
 118     // InputMethodRequests implementation
 119     public Point2D getTextLocation(int offset) {
 120         int[] loc = webPage.getClientTextLocation(offset);
 121         WCPoint point = webPage.getPageClient().windowToScreen(
 122                 // We need lower left corner of the char bounds rectangle here
 123                 new WCPoint(loc[0], loc[1] + loc[3]));
 124         return new Point2D(point.getIntX(), point.getIntY());
 125     }
 126 
 127     public int getLocationOffset(int x, int y) {
 128         WCPoint point = webPage.getPageClient().windowToScreen(new WCPoint(0, 0));
 129         return webPage.getClientLocationOffset(x - point.getIntX(), y - point.getIntY());
 130     }
 131 
 132     public void cancelLatestCommittedText() {
 133         // "Undo commit" is not supported.
 134     }
 135 
 136     public String getSelectedText() {
 137         return webPage.getClientSelectedText();
 138     }
 139 
 140     @Override
 141     public int getInsertPositionOffset() {
 142         return webPage.getClientInsertPositionOffset();
 143     }
 144 
 145     @Override
 146     public String getCommittedText(int begin, int end) {
 147         try {
 148             return webPage.getClientCommittedText().substring(begin, end);
 149         } catch (StringIndexOutOfBoundsException e) {
 150             throw new IllegalArgumentException(e);
 151         }
 152     }
 153 
 154     @Override
 155     public int getCommittedTextLength() {
 156         return webPage.getClientCommittedTextLength();
 157     }
 158 }