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 }