|
1 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
2 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
4 "use strict"; |
|
5 |
|
6 require("sdk/clipboard"); |
|
7 |
|
8 const { Cc, Ci } = require("chrome"); |
|
9 |
|
10 const imageTools = Cc["@mozilla.org/image/tools;1"]. |
|
11 getService(Ci.imgITools); |
|
12 |
|
13 const io = Cc["@mozilla.org/network/io-service;1"]. |
|
14 getService(Ci.nsIIOService); |
|
15 |
|
16 const base64png = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYA" + |
|
17 "AABzenr0AAAASUlEQVRYhe3O0QkAIAwD0eyqe3Q993AQ3cBSUKpygfsNTy" + |
|
18 "N5ugbQpK0BAADgP0BRDWXWlwEAAAAAgPsA3rzDaAAAAHgPcGrpgAnzQ2FG" + |
|
19 "bWRR9AAAAABJRU5ErkJggg%3D%3D"; |
|
20 |
|
21 const base64jpeg = "data:image/jpeg;base64,%2F9j%2F4AAQSkZJRgABAQAAAQABAAD%2F" + |
|
22 "2wBDAAMCAgICAgMCAgIDAwMDBAYEBAQEBAgGBgUGCQgKCgkICQkKDA8MCg" + |
|
23 "sOCwkJDRENDg8QEBEQCgwSExIQEw8QEBD%2F2wBDAQMDAwQDBAgEBAgQCw" + |
|
24 "kLEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQ" + |
|
25 "EBAQEBAQEBD%2FwAARCAAgACADAREAAhEBAxEB%2F8QAHwAAAQUBAQEBAQ" + |
|
26 "EAAAAAAAAAAAECAwQFBgcICQoL%2F8QAtRAAAgEDAwIEAwUFBAQAAAF9AQ" + |
|
27 "IDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRol" + |
|
28 "JicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eX" + |
|
29 "qDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJ" + |
|
30 "ytLT1NXW19jZ2uHi4%2BTl5ufo6erx8vP09fb3%2BPn6%2F8QAHwEAAwEB" + |
|
31 "AQEBAQEBAQAAAAAAAAECAwQFBgcICQoL%2F8QAtREAAgECBAQDBAcFBAQA" + |
|
32 "AQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNO" + |
|
33 "El8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0" + |
|
34 "dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6ws" + |
|
35 "PExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3%2BPn6%2F9oADAMB" + |
|
36 "AAIRAxEAPwD5Kr8kP9CwoA5f4m%2F8iRqX%2FbH%2FANHJXr5F%2FwAjCn" + |
|
37 "8%2F%2FSWfnnir%2FwAkji%2F%2B4f8A6dgeD1%2BiH8bn1BX5If6FmFqW" + |
|
38 "pXtveyQwzbUXGBtB7D2r9l4U4UyjMsoo4rFUeacua75pLaUktFJLZH5NxN" + |
|
39 "xNmmX5pVw2Gq8sI8tlyxe8U3q03uzD8S3dxqOi3NneSeZDJs3LgDOHBHI5" + |
|
40 "6gV%2BkcG%2BH%2FDmJzuhSq4e8XzfbqfyS%2FvH5rx1xTm2MyDEUa1W8X" + |
|
41 "yXXLFbTi%2BkThv7B0r%2FAJ9f%2FH2%2Fxr90%2FwCIVcI%2F9An%2FAJ" + |
|
42 "Uq%2FwDyZ%2FO%2F16v%2FADfgv8j0r%2FhZvgj%2FAKDf%2FktN%2FwDE" + |
|
43 "V%2Fnr%2FYWYf8%2B%2Fxj%2Fmf3R%2FxFXhH%2FoL%2FwDKdX%2F5Azrv" + |
|
44 "xLouo3D3lne%2BZDJja3luM4GDwRnqDX9LeH%2FBud4nhzD1aVC8Xz%2Fa" + |
|
45 "h%2Fz8l%2FePx%2FinjrIMZm1WtRxF4vls%2BSa2jFdYlDUdRsp7OSKKbc" + |
|
46 "7YwNpHce1fqfCvCub5bm9HFYqjywjzXfNF7xklopN7s%2BC4l4lyvMMrq4" + |
|
47 "fD1bzfLZcsltJPqktkYlfsZ%2BUnBV%2FnufVnXaD%2FAMgqD%2FgX%2Fo" + |
|
48 "Rr%2BxvCr%2FkkcJ%2F3E%2F8ATsz5%2FHfx5fL8kX6%2FQjkCgD%2F%2F" + |
|
49 "2Q%3D%3D"; |
|
50 |
|
51 const canvasHTML = "data:text/html," + encodeURIComponent( |
|
52 "<html>\ |
|
53 <body>\ |
|
54 <canvas width='32' height='32'></canvas>\ |
|
55 </body>\ |
|
56 </html>" |
|
57 ); |
|
58 |
|
59 function comparePixelImages(imageA, imageB, callback) { |
|
60 let tabs = require("sdk/tabs"); |
|
61 |
|
62 tabs.open({ |
|
63 url: canvasHTML, |
|
64 |
|
65 onReady: function onReady(tab) { |
|
66 let worker = tab.attach({ |
|
67 contentScript: "new " + function() { |
|
68 let canvas = document.querySelector("canvas"); |
|
69 let context = canvas.getContext("2d"); |
|
70 |
|
71 self.port.on("draw-image", function(imageURI) { |
|
72 let img = new Image(); |
|
73 |
|
74 img.onload = function() { |
|
75 context.drawImage(this, 0, 0); |
|
76 |
|
77 let pixels = Array.join(context.getImageData(0, 0, 32, 32).data); |
|
78 self.port.emit("image-pixels", pixels); |
|
79 } |
|
80 |
|
81 img.src = imageURI; |
|
82 }); |
|
83 } |
|
84 }); |
|
85 |
|
86 let compared = ""; |
|
87 |
|
88 worker.port.on("image-pixels", function (pixels) { |
|
89 if (!compared) { |
|
90 compared = pixels; |
|
91 this.emit("draw-image", imageB); |
|
92 } else { |
|
93 callback(compared === pixels); |
|
94 tab.close() |
|
95 } |
|
96 }); |
|
97 |
|
98 worker.port.emit("draw-image", imageA); |
|
99 } |
|
100 }); |
|
101 } |
|
102 |
|
103 |
|
104 // Test the typical use case, setting & getting with no flavors specified |
|
105 exports["test With No Flavor"] = function(assert) { |
|
106 var contents = "hello there"; |
|
107 var flavor = "text"; |
|
108 var fullFlavor = "text/unicode"; |
|
109 var clip = require("sdk/clipboard"); |
|
110 |
|
111 // Confirm we set the clipboard |
|
112 assert.ok(clip.set(contents)); |
|
113 |
|
114 // Confirm flavor is set |
|
115 assert.equal(clip.currentFlavors[0], flavor); |
|
116 |
|
117 // Confirm we set the clipboard |
|
118 assert.equal(clip.get(), contents); |
|
119 |
|
120 // Confirm we can get the clipboard using the flavor |
|
121 assert.equal(clip.get(flavor), contents); |
|
122 |
|
123 // Confirm we can still get the clipboard using the full flavor |
|
124 assert.equal(clip.get(fullFlavor), contents); |
|
125 }; |
|
126 |
|
127 // Test the slightly less common case where we specify the flavor |
|
128 exports["test With Flavor"] = function(assert) { |
|
129 var contents = "<b>hello there</b>"; |
|
130 var contentsText = "hello there"; |
|
131 var flavor = "html"; |
|
132 var fullFlavor = "text/html"; |
|
133 var unicodeFlavor = "text"; |
|
134 var unicodeFullFlavor = "text/unicode"; |
|
135 var clip = require("sdk/clipboard"); |
|
136 |
|
137 assert.ok(clip.set(contents, flavor)); |
|
138 |
|
139 assert.equal(clip.currentFlavors[0], unicodeFlavor); |
|
140 assert.equal(clip.currentFlavors[1], flavor); |
|
141 assert.equal(clip.get(), contentsText); |
|
142 assert.equal(clip.get(flavor), contents); |
|
143 assert.equal(clip.get(fullFlavor), contents); |
|
144 assert.equal(clip.get(unicodeFlavor), contentsText); |
|
145 assert.equal(clip.get(unicodeFullFlavor), contentsText); |
|
146 }; |
|
147 |
|
148 // Test that the typical case still works when we specify the flavor to set |
|
149 exports["test With Redundant Flavor"] = function(assert) { |
|
150 var contents = "<b>hello there</b>"; |
|
151 var flavor = "text"; |
|
152 var fullFlavor = "text/unicode"; |
|
153 var clip = require("sdk/clipboard"); |
|
154 |
|
155 assert.ok(clip.set(contents, flavor)); |
|
156 assert.equal(clip.currentFlavors[0], flavor); |
|
157 assert.equal(clip.get(), contents); |
|
158 assert.equal(clip.get(flavor), contents); |
|
159 assert.equal(clip.get(fullFlavor), contents); |
|
160 }; |
|
161 |
|
162 exports["test Not In Flavor"] = function(assert) { |
|
163 var contents = "hello there"; |
|
164 var flavor = "html"; |
|
165 var clip = require("sdk/clipboard"); |
|
166 |
|
167 assert.ok(clip.set(contents)); |
|
168 // If there's nothing on the clipboard with this flavor, should return null |
|
169 assert.equal(clip.get(flavor), null); |
|
170 }; |
|
171 |
|
172 exports["test Set Image"] = function(assert) { |
|
173 var clip = require("sdk/clipboard"); |
|
174 var flavor = "image"; |
|
175 var fullFlavor = "image/png"; |
|
176 |
|
177 assert.ok(clip.set(base64png, flavor), "clipboard set"); |
|
178 assert.equal(clip.currentFlavors[0], flavor, "flavor is set"); |
|
179 }; |
|
180 |
|
181 exports["test Get Image"] = function(assert, done) { |
|
182 var clip = require("sdk/clipboard"); |
|
183 |
|
184 clip.set(base64png, "image"); |
|
185 |
|
186 var contents = clip.get(); |
|
187 |
|
188 comparePixelImages(base64png, contents, function (areEquals) { |
|
189 assert.ok(areEquals, |
|
190 "Image gets from clipboard equals to image sets to the clipboard"); |
|
191 |
|
192 done(); |
|
193 }); |
|
194 } |
|
195 |
|
196 exports["test Set Image Type Not Supported"] = function(assert) { |
|
197 var clip = require("sdk/clipboard"); |
|
198 var flavor = "image"; |
|
199 |
|
200 assert.throws(function () { |
|
201 clip.set(base64jpeg, flavor); |
|
202 }, "Invalid flavor for image/jpeg"); |
|
203 |
|
204 }; |
|
205 |
|
206 // Notice that `imageTools.decodeImageData`, used by `clipboard.set` method for |
|
207 // images, write directly to the javascript console the error in case the image |
|
208 // is corrupt, even if the error is catched. |
|
209 // |
|
210 // See: http://mxr.mozilla.org/mozilla-central/source/image/src/Decoder.cpp#136 |
|
211 exports["test Set Image Type Wrong Data"] = function(assert) { |
|
212 var clip = require("sdk/clipboard"); |
|
213 var flavor = "image"; |
|
214 |
|
215 var wrongPNG = "data:image/png" + base64jpeg.substr(15); |
|
216 |
|
217 assert.throws(function () { |
|
218 clip.set(wrongPNG, flavor); |
|
219 }, "Unable to decode data given in a valid image."); |
|
220 }; |
|
221 |
|
222 require("test").run(exports) |