• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2008, The Android Open Source Project
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *  * Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  *  * Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25 
26 #include "FormPlugin.h"
27 
28 #include <stdio.h>
29 #include <sys/time.h>
30 #include <time.h>
31 #include <math.h>
32 #include <string.h>
33 
34 extern NPNetscapeFuncs*         browser;
35 extern ANPLogInterfaceV0        gLogI;
36 extern ANPCanvasInterfaceV0     gCanvasI;
37 extern ANPPaintInterfaceV0      gPaintI;
38 extern ANPTypefaceInterfaceV0   gTypefaceI;
39 extern ANPWindowInterfaceV0     gWindowI;
40 
41 
inval(NPP instance)42 static void inval(NPP instance) {
43     browser->invalidaterect(instance, NULL);
44 }
45 
rnd16(float x,int inset)46 static uint16_t rnd16(float x, int inset) {
47     int ix = (int)roundf(x) + inset;
48     if (ix < 0) {
49         ix = 0;
50     }
51     return static_cast<uint16_t>(ix);
52 }
53 
inval(NPP instance,const ANPRectF & r,bool doAA)54 static void inval(NPP instance, const ANPRectF& r, bool doAA) {
55     const int inset = doAA ? -1 : 0;
56 
57     PluginObject *obj = reinterpret_cast<PluginObject*>(instance->pdata);
58     NPRect inval;
59     inval.left = rnd16(r.left, inset);
60     inval.top = rnd16(r.top, inset);
61     inval.right = rnd16(r.right, -inset);
62     inval.bottom = rnd16(r.bottom, -inset);
63     browser->invalidaterect(instance, &inval);
64 }
65 
66 ///////////////////////////////////////////////////////////////////////////////
67 
FormPlugin(NPP inst)68 FormPlugin::FormPlugin(NPP inst) : SubPlugin(inst) {
69 
70     m_hasFocus = false;
71     m_activeInput = NULL;
72 
73     memset(&m_usernameInput, 0, sizeof(m_usernameInput));
74     memset(&m_passwordInput, 0, sizeof(m_passwordInput));
75 
76     m_usernameInput.text[0] = '\0';
77     m_usernameInput.charPtr = 0;
78 
79     m_passwordInput.text[0] = '\0';
80     m_passwordInput.charPtr = 0;
81 
82     m_paintInput = gPaintI.newPaint();
83     gPaintI.setFlags(m_paintInput, gPaintI.getFlags(m_paintInput) | kAntiAlias_ANPPaintFlag);
84     gPaintI.setColor(m_paintInput, 0xFFFFFFFF);
85 
86     m_paintActive = gPaintI.newPaint();
87     gPaintI.setFlags(m_paintActive, gPaintI.getFlags(m_paintActive) | kAntiAlias_ANPPaintFlag);
88     gPaintI.setColor(m_paintActive, 0xFFFFFF00);
89 
90     m_paintText = gPaintI.newPaint();
91     gPaintI.setFlags(m_paintText, gPaintI.getFlags(m_paintText) | kAntiAlias_ANPPaintFlag);
92     gPaintI.setColor(m_paintText, 0xFF000000);
93     gPaintI.setTextSize(m_paintText, 18);
94 
95     ANPTypeface* tf = gTypefaceI.createFromName("serif", kItalic_ANPTypefaceStyle);
96     gPaintI.setTypeface(m_paintText, tf);
97     gTypefaceI.unref(tf);
98 
99     //register for key and visibleRect events
100     ANPEventFlags flags = kKey_ANPEventFlag;
101     NPError err = browser->setvalue(inst, kAcceptEvents_ANPSetValue, &flags);
102     if (err != NPERR_NO_ERROR) {
103         gLogI.log(kError_ANPLogType, "Error selecting input events.");
104     }
105 }
106 
~FormPlugin()107 FormPlugin::~FormPlugin() {
108     gPaintI.deletePaint(m_paintInput);
109     gPaintI.deletePaint(m_paintActive);
110     gPaintI.deletePaint(m_paintText);
111 }
112 
supportsDrawingModel(ANPDrawingModel model)113 bool FormPlugin::supportsDrawingModel(ANPDrawingModel model) {
114     return (model == kBitmap_ANPDrawingModel);
115 }
116 
drawPlugin(const ANPBitmap & bitmap,const ANPRectI & clip)117 void FormPlugin::drawPlugin(const ANPBitmap& bitmap, const ANPRectI& clip) {
118     ANPCanvas* canvas = gCanvasI.newCanvas(&bitmap);
119 
120     ANPRectF clipR;
121     clipR.left = clip.left;
122     clipR.top = clip.top;
123     clipR.right = clip.right;
124     clipR.bottom = clip.bottom;
125     gCanvasI.clipRect(canvas, &clipR);
126 
127     draw(canvas);
128     gCanvasI.deleteCanvas(canvas);
129 }
130 
draw(ANPCanvas * canvas)131 void FormPlugin::draw(ANPCanvas* canvas) {
132     NPP instance = this->inst();
133     PluginObject *obj = (PluginObject*) instance->pdata;
134 
135     const float inputWidth = 60;
136     const float inputHeight = 30;
137     const int W = obj->window->width;
138     const int H = obj->window->height;
139 
140     // color the plugin canvas
141     gCanvasI.drawColor(canvas, (m_hasFocus) ? 0xFFCDCDCD : 0xFF545454);
142 
143     // draw the username box (5 px from the top edge)
144     m_usernameInput.rect.left = 5;
145     m_usernameInput.rect.top = 5;
146     m_usernameInput.rect.right = W - 5;
147     m_usernameInput.rect.bottom = m_usernameInput.rect.top + inputHeight;
148     gCanvasI.drawRect(canvas, &m_usernameInput.rect, getPaint(&m_usernameInput));
149     drawText(canvas, m_usernameInput);
150 
151     // draw the password box (5 px from the bottom edge)
152     m_passwordInput.rect.left = 5;
153     m_passwordInput.rect.top = H - (inputHeight + 5);
154     m_passwordInput.rect.right = W - 5;
155     m_passwordInput.rect.bottom = m_passwordInput.rect.top + inputHeight;
156     gCanvasI.drawRect(canvas, &m_passwordInput.rect, getPaint(&m_passwordInput));
157     drawPassword(canvas, m_passwordInput);
158 
159     //invalidate the canvas
160     //inval(instance);
161 }
162 
getPaint(TextInput * input)163 ANPPaint* FormPlugin::getPaint(TextInput* input) {
164     return (input == m_activeInput) ? m_paintActive : m_paintInput;
165 }
166 
drawText(ANPCanvas * canvas,TextInput textInput)167 void FormPlugin::drawText(ANPCanvas* canvas, TextInput textInput) {
168 
169     // get font metrics
170     ANPFontMetrics fontMetrics;
171     gPaintI.getFontMetrics(m_paintText, &fontMetrics);
172 
173     gCanvasI.drawText(canvas, textInput.text, textInput.charPtr,
174                       textInput.rect.left + 5,
175                       textInput.rect.bottom - fontMetrics.fBottom, m_paintText);
176 }
177 
drawPassword(ANPCanvas * canvas,TextInput passwordInput)178 void FormPlugin::drawPassword(ANPCanvas* canvas, TextInput passwordInput) {
179 
180     // get font metrics
181     ANPFontMetrics fontMetrics;
182     gPaintI.getFontMetrics(m_paintText, &fontMetrics);
183 
184     // comput the circle dimensions and initial location
185     float initialX = passwordInput.rect.left + 5;
186     float ovalBottom = passwordInput.rect.bottom - 2;
187     float ovalTop = ovalBottom - (fontMetrics.fBottom - fontMetrics.fTop);
188     float ovalWidth = ovalBottom - ovalTop;
189     float ovalSpacing = 3;
190 
191     // draw circles instead of the actual text
192     for (uint32_t x = 0; x < passwordInput.charPtr; x++) {
193         ANPRectF oval;
194         oval.left = initialX + ((ovalWidth + ovalSpacing) * (float) x);
195         oval.right = oval.left + ovalWidth;
196         oval.top = ovalTop;
197         oval.bottom = ovalBottom;
198         gCanvasI.drawOval(canvas, &oval, m_paintText);
199     }
200 }
201 
handleEvent(const ANPEvent * evt)202 int16_t FormPlugin::handleEvent(const ANPEvent* evt) {
203     NPP instance = this->inst();
204 
205     switch (evt->eventType) {
206         case kDraw_ANPEventType:
207             switch (evt->data.draw.model) {
208                 case kBitmap_ANPDrawingModel:
209                     drawPlugin(evt->data.draw.data.bitmap, evt->data.draw.clip);
210                     return 1;
211                 default:
212                     break;   // unknown drawing model
213             }
214             break;
215 
216         case kLifecycle_ANPEventType:
217             if (evt->data.lifecycle.action == kLoseFocus_ANPLifecycleAction) {
218                 gLogI.log(kDebug_ANPLogType, "----%p Loosing Focus", instance);
219 
220                 if (m_activeInput) {
221                     // hide the keyboard
222                     gWindowI.showKeyboard(instance, false);
223 
224                     //reset the activeInput
225                     m_activeInput = NULL;
226                 }
227 
228                 m_hasFocus = false;
229                 inval(instance);
230                 return 1;
231             }
232             else if (evt->data.lifecycle.action == kGainFocus_ANPLifecycleAction) {
233                 gLogI.log(kDebug_ANPLogType, "----%p Gaining Focus", instance);
234                 m_hasFocus = true;
235                 inval(instance);
236                 return 1;
237             }
238             break;
239 
240         case kMouse_ANPEventType: {
241 
242             int x = evt->data.mouse.x;
243             int y = evt->data.mouse.y;
244             if (kDown_ANPMouseAction == evt->data.mouse.action) {
245 
246                 TextInput* currentInput = validTap(x,y);
247 
248                 if (currentInput)
249                     gWindowI.showKeyboard(instance, true);
250                 else if (m_activeInput)
251                     gWindowI.showKeyboard(instance, false);
252 
253                 if (currentInput != m_activeInput)
254                     switchActiveInput(currentInput);
255 
256                 return 1;
257             }
258             break;
259         }
260 
261         case kKey_ANPEventType:
262             if (evt->data.key.action == kDown_ANPKeyAction) {
263 
264                 //handle navigation keys
265                 if (evt->data.key.nativeCode >= kDpadUp_ANPKeyCode
266                         && evt->data.key.nativeCode <= kDpadCenter_ANPKeyCode) {
267                     return handleNavigation(evt->data.key.nativeCode) ? 1 : 0;
268                 }
269 
270                 if (m_activeInput) {
271                     handleTextInput(m_activeInput, evt->data.key.nativeCode,
272                                     evt->data.key.unichar);
273                     inval(instance, m_activeInput->rect, true);
274                 }
275             }
276             return 1;
277 
278         default:
279             break;
280     }
281     return 0;   // unknown or unhandled event
282 }
283 
switchActiveInput(TextInput * newInput)284 void FormPlugin::switchActiveInput(TextInput* newInput) {
285     NPP instance = this->inst();
286 
287     if (m_activeInput) {
288         inval(instance, m_activeInput->rect, true); // inval the old
289         gWindowI.clearVisibleRects(instance);
290     }
291 
292     m_activeInput = newInput; // set the new active input
293 
294     if (m_activeInput) {
295         inval(instance, m_activeInput->rect, true); // inval the new
296         scrollIntoView(m_activeInput);
297     }
298 }
299 
handleNavigation(ANPKeyCode keyCode)300 bool FormPlugin::handleNavigation(ANPKeyCode keyCode) {
301     NPP instance = this->inst();
302 
303     gLogI.log(kDebug_ANPLogType, "----%p Recvd Nav Key %d", instance, keyCode);
304 
305     if (!m_activeInput) {
306         gWindowI.showKeyboard(instance, true);
307         switchActiveInput(&m_usernameInput);
308     }
309     else if (m_activeInput == &m_usernameInput) {
310         if (keyCode == kDpadDown_ANPKeyCode) {
311             switchActiveInput(&m_passwordInput);
312         }
313         else if (keyCode == kDpadCenter_ANPKeyCode)
314             gWindowI.showKeyboard(instance, false);
315         else if (keyCode == kDpadUp_ANPKeyCode)
316             return false;
317     }
318     else if (m_activeInput == &m_passwordInput) {
319         if (keyCode == kDpadUp_ANPKeyCode) {
320             switchActiveInput(&m_usernameInput);
321         }
322         else if (keyCode == kDpadCenter_ANPKeyCode)
323             gWindowI.showKeyboard(instance, false);
324         else if (keyCode == kDpadDown_ANPKeyCode)
325             return false;
326     }
327 
328     return true;
329 }
330 
handleTextInput(TextInput * input,ANPKeyCode keyCode,int32_t unichar)331 void FormPlugin::handleTextInput(TextInput* input, ANPKeyCode keyCode, int32_t unichar) {
332     NPP instance = this->inst();
333 
334     //make sure the input field is in view
335     scrollIntoView(input);
336 
337     //handle the delete operation
338     if (keyCode == kDel_ANPKeyCode) {
339         if (input->charPtr > 0) {
340             input->charPtr--;
341         }
342         return;
343     }
344 
345     //check to see that the input is not full
346     if (input->charPtr >= (sizeof(input->text) - 1))
347         return;
348 
349     //add the character
350     input->text[input->charPtr] = static_cast<char>(unichar);
351     input->charPtr++;
352 
353     gLogI.log(kDebug_ANPLogType, "----%p Text:  %c", instance, unichar);
354 }
355 
scrollIntoView(TextInput * input)356 void FormPlugin::scrollIntoView(TextInput* input) {
357     NPP instance = this->inst();
358     PluginObject *obj = (PluginObject*) instance->pdata;
359     NPWindow *window = obj->window;
360 
361     // find the textInput's global rect coordinates
362     ANPRectI visibleRects[1];
363     visibleRects[0].left = input->rect.left;
364     visibleRects[0].top = input->rect.top;
365     visibleRects[0].right = input->rect.right;
366     visibleRects[0].bottom = input->rect.bottom;
367 
368     gWindowI.setVisibleRects(instance, visibleRects, 1);
369 }
370 
validTap(int x,int y)371 TextInput* FormPlugin::validTap(int x, int y) {
372 
373     if (x > m_usernameInput.rect.left && x < m_usernameInput.rect.right &&
374         y > m_usernameInput.rect.top && y < m_usernameInput.rect.bottom)
375         return &m_usernameInput;
376     else if (x >m_passwordInput.rect.left && x < m_passwordInput.rect.right &&
377              y > m_passwordInput.rect.top && y < m_passwordInput.rect.bottom)
378         return &m_passwordInput;
379     else
380         return NULL;
381 }
382