Add copy of .ttf font with .eot extension for testing
[wine-gecko.git] / widget / src / xpwidgets / nsPrimitiveHelpers.cpp
blobc206e22823e742922342dc555b3ab7fca33d787d
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
3 * ***** BEGIN LICENSE BLOCK *****
4 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 * The contents of this file are subject to the Mozilla Public License Version
7 * 1.1 (the "License"); you may not use this file except in compliance with
8 * the License. You may obtain a copy of the License at
9 * http://www.mozilla.org/MPL/
11 * Software distributed under the License is distributed on an "AS IS" basis,
12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 * for the specific language governing rights and limitations under the
14 * License.
16 * The Original Code is Mozilla Communicator.
18 * The Initial Developer of the Original Code is
19 * Netscape Communications Corp.
20 * Portions created by the Initial Developer are Copyright (C) 1999
21 * the Initial Developer. All Rights Reserved.
23 * Contributor(s):
24 * Mike Pinkerton
26 * Alternatively, the contents of this file may be used under the terms of
27 * either the GNU General Public License Version 2 or later (the "GPL"), or
28 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 * in which case the provisions of the GPL or the LGPL are applicable instead
30 * of those above. If you wish to allow use of your version of this file only
31 * under the terms of either the GPL or the LGPL, and not to allow others to
32 * use your version of this file under the terms of the MPL, indicate your
33 * decision by deleting the provisions above and replace them with the notice
34 * and other provisions required by the GPL or the LGPL. If you do not delete
35 * the provisions above, a recipient may use your version of this file under
36 * the terms of any one of the MPL, the GPL or the LGPL.
38 * ***** END LICENSE BLOCK ***** */
42 // Part of the reason these routines are all in once place is so that as new
43 // data flavors are added that are known to be one-byte or two-byte strings, or even
44 // raw binary data, then we just have to go to one place to change how the data
45 // moves into/out of the primitives and native line endings.
47 // If you add new flavors that have special consideration (binary data or one-byte
48 // char* strings), please update all the helper classes in this file.
50 // For now, this is the assumption that we are making:
51 // - text/plain is always a char*
52 // - anything else is a PRUnichar*
56 #include "nsPrimitiveHelpers.h"
57 #include "nsCOMPtr.h"
58 #include "nsXPCOM.h"
59 #include "nsISupportsPrimitives.h"
60 #include "nsITransferable.h"
61 #include "nsIComponentManager.h"
62 #include "nsLinebreakConverter.h"
63 #include "nsReadableUtils.h"
65 #include "nsIServiceManager.h"
66 #include "nsICharsetConverterManager.h"
67 // unicode conversion
68 # include "nsIPlatformCharset.h"
69 #include "nsISaveAsCharset.h"
70 #include "nsAutoPtr.h"
74 // CreatePrimitiveForData
76 // Given some data and the flavor it corresponds to, creates the appropriate
77 // nsISupports* wrapper for passing across IDL boundaries. Right now, everything
78 // creates a two-byte |nsISupportsString|, except for "text/plain" and native
79 // platform HTML (CF_HTML on win32)
81 void
82 nsPrimitiveHelpers :: CreatePrimitiveForData ( const char* aFlavor, void* aDataBuff,
83 PRUint32 aDataLen, nsISupports** aPrimitive )
85 if ( !aPrimitive )
86 return;
88 if ( strcmp(aFlavor,kTextMime) == 0 || strcmp(aFlavor,kNativeHTMLMime) == 0 ) {
89 nsCOMPtr<nsISupportsCString> primitive =
90 do_CreateInstance(NS_SUPPORTS_CSTRING_CONTRACTID);
91 if ( primitive ) {
92 const char * start = reinterpret_cast<const char*>(aDataBuff);
93 primitive->SetData(Substring(start, start + aDataLen));
94 NS_ADDREF(*aPrimitive = primitive);
97 else {
98 nsCOMPtr<nsISupportsString> primitive =
99 do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID);
100 if (primitive ) {
101 if (aDataLen % 2) {
102 nsAutoArrayPtr<char> buffer(new char[aDataLen + 1]);
103 if (!NS_LIKELY(buffer))
104 return;
106 memcpy(buffer, aDataBuff, aDataLen);
107 buffer[aDataLen] = 0;
108 const PRUnichar* start = reinterpret_cast<const PRUnichar*>(buffer.get());
109 // recall that length takes length as characters, not bytes
110 primitive->SetData(Substring(start, start + (aDataLen + 1) / 2));
111 } else {
112 const PRUnichar* start = reinterpret_cast<const PRUnichar*>(aDataBuff);
113 // recall that length takes length as characters, not bytes
114 primitive->SetData(Substring(start, start + (aDataLen / 2)));
116 NS_ADDREF(*aPrimitive = primitive);
120 } // CreatePrimitiveForData
124 // CreateDataFromPrimitive
126 // Given a nsISupports* primitive and the flavor it represents, creates a new data
127 // buffer with the data in it. This data will be null terminated, but the length
128 // parameter does not reflect that.
130 void
131 nsPrimitiveHelpers :: CreateDataFromPrimitive ( const char* aFlavor, nsISupports* aPrimitive,
132 void** aDataBuff, PRUint32 aDataLen )
134 if ( !aDataBuff )
135 return;
137 *aDataBuff = nsnull;
139 if ( strcmp(aFlavor,kTextMime) == 0 ) {
140 nsCOMPtr<nsISupportsCString> plainText ( do_QueryInterface(aPrimitive) );
141 if ( plainText ) {
142 nsCAutoString data;
143 plainText->GetData ( data );
144 *aDataBuff = ToNewCString(data);
147 else {
148 nsCOMPtr<nsISupportsString> doubleByteText ( do_QueryInterface(aPrimitive) );
149 if ( doubleByteText ) {
150 nsAutoString data;
151 doubleByteText->GetData ( data );
152 *aDataBuff = ToNewUnicode(data);
160 // ConvertUnicodeToPlatformPlainText
162 // Given a unicode buffer (flavor text/unicode), this converts it to plain text using
163 // the appropriate platform charset encoding. |inUnicodeLen| is the length of the input
164 // string, not the # of bytes in the buffer. The |outPlainTextData| is null terminated,
165 // but its length parameter, |outPlainTextLen|, does not reflect that.
167 nsresult
168 nsPrimitiveHelpers :: ConvertUnicodeToPlatformPlainText ( PRUnichar* inUnicode, PRInt32 inUnicodeLen,
169 char** outPlainTextData, PRInt32* outPlainTextLen )
171 if ( !outPlainTextData || !outPlainTextLen )
172 return NS_ERROR_INVALID_ARG;
174 // get the charset
175 nsresult rv;
176 nsCOMPtr <nsIPlatformCharset> platformCharsetService = do_GetService(NS_PLATFORMCHARSET_CONTRACTID, &rv);
178 nsCAutoString platformCharset;
179 if (NS_SUCCEEDED(rv))
180 rv = platformCharsetService->GetCharset(kPlatformCharsetSel_PlainTextInClipboard, platformCharset);
181 if (NS_FAILED(rv))
182 platformCharset.AssignLiteral("ISO-8859-1");
184 // use transliterate to convert things like smart quotes to normal quotes for plain text
186 nsCOMPtr<nsISaveAsCharset> converter = do_CreateInstance("@mozilla.org/intl/saveascharset;1", &rv);
187 NS_ENSURE_SUCCESS(rv, rv);
189 rv = converter->Init(platformCharset.get(),
190 nsISaveAsCharset::attr_EntityAfterCharsetConv +
191 nsISaveAsCharset::attr_FallbackQuestionMark,
192 nsIEntityConverter::transliterate);
193 NS_ENSURE_SUCCESS(rv, rv);
195 rv = converter->Convert(inUnicode, outPlainTextData);
196 *outPlainTextLen = *outPlainTextData ? strlen(*outPlainTextData) : 0;
198 NS_ASSERTION ( NS_SUCCEEDED(rv), "Error converting unicode to plain text" );
200 return rv;
201 } // ConvertUnicodeToPlatformPlainText
205 // ConvertPlatformPlainTextToUnicode
207 // Given a char buffer (flavor text/plaikn), this converts it to unicode using
208 // the appropriate platform charset encoding. |outUnicode| is null terminated,
209 // but its length parameter, |outUnicodeLen|, does not reflect that. |outUnicodeLen| is
210 // the length of the string in characters, not bytes.
212 nsresult
213 nsPrimitiveHelpers :: ConvertPlatformPlainTextToUnicode ( const char* inText, PRInt32 inTextLen,
214 PRUnichar** outUnicode, PRInt32* outUnicodeLen )
216 if ( !outUnicode || !outUnicodeLen )
217 return NS_ERROR_INVALID_ARG;
219 // Get the appropriate unicode decoder. We're guaranteed that this won't change
220 // through the life of the app so we can cache it.
221 nsresult rv = NS_OK;
222 static nsCOMPtr<nsIUnicodeDecoder> decoder;
223 static PRBool hasConverter = PR_FALSE;
224 if ( !hasConverter ) {
225 // get the charset
226 nsCAutoString platformCharset;
227 nsCOMPtr <nsIPlatformCharset> platformCharsetService = do_GetService(NS_PLATFORMCHARSET_CONTRACTID, &rv);
228 if (NS_SUCCEEDED(rv))
229 rv = platformCharsetService->GetCharset(kPlatformCharsetSel_PlainTextInClipboard, platformCharset);
230 if (NS_FAILED(rv))
231 platformCharset.AssignLiteral("ISO-8859-1");
233 // get the decoder
234 nsCOMPtr<nsICharsetConverterManager> ccm =
235 do_GetService(NS_CHARSETCONVERTERMANAGER_CONTRACTID, &rv);
236 rv = ccm->GetUnicodeDecoderRaw(platformCharset.get(),
237 getter_AddRefs(decoder));
239 NS_ASSERTION(NS_SUCCEEDED(rv), "GetUnicodeEncoderRaw failed.");
240 if (NS_FAILED(rv))
241 return NS_ERROR_FAILURE;
243 hasConverter = PR_TRUE;
246 // Estimate out length and allocate the buffer based on a worst-case estimate, then do
247 // the conversion.
248 decoder->GetMaxLength(inText, inTextLen, outUnicodeLen); // |outUnicodeLen| is number of chars
249 if ( *outUnicodeLen ) {
250 *outUnicode = reinterpret_cast<PRUnichar*>(nsMemory::Alloc((*outUnicodeLen + 1) * sizeof(PRUnichar)));
251 if ( *outUnicode ) {
252 rv = decoder->Convert(inText, &inTextLen, *outUnicode, outUnicodeLen);
253 (*outUnicode)[*outUnicodeLen] = '\0'; // null terminate. Convert() doesn't do it for us
255 } // if valid length
257 NS_ASSERTION ( NS_SUCCEEDED(rv), "Error converting plain text to unicode" );
259 return rv;
260 } // ConvertPlatformPlainTextToUnicode
263 #ifdef XP_MAC
264 #pragma mark -
265 #endif
269 // ConvertPlatformToDOMLinebreaks
271 // Given some data, convert from the platform linebreaks into the LF expected by the
272 // DOM. This will attempt to convert the data in place, but the buffer may still need to
273 // be reallocated regardless (disposing the old buffer is taken care of internally, see
274 // the note below).
276 // NOTE: this assumes that it can use nsMemory to dispose of the old buffer.
278 nsresult
279 nsLinebreakHelpers :: ConvertPlatformToDOMLinebreaks ( const char* inFlavor, void** ioData,
280 PRInt32* ioLengthInBytes )
282 NS_ASSERTION ( ioData && *ioData && ioLengthInBytes, "Bad Params");
283 if ( !(ioData && *ioData && ioLengthInBytes) )
284 return NS_ERROR_INVALID_ARG;
286 nsresult retVal = NS_OK;
288 if ( strcmp(inFlavor, "text/plain") == 0 ) {
289 char* buffAsChars = reinterpret_cast<char*>(*ioData);
290 char* oldBuffer = buffAsChars;
291 retVal = nsLinebreakConverter::ConvertLineBreaksInSitu ( &buffAsChars, nsLinebreakConverter::eLinebreakAny,
292 nsLinebreakConverter::eLinebreakContent,
293 *ioLengthInBytes, ioLengthInBytes );
294 if ( NS_SUCCEEDED(retVal) ) {
295 if ( buffAsChars != oldBuffer ) // check if buffer was reallocated
296 nsMemory::Free ( oldBuffer );
297 *ioData = buffAsChars;
300 else if ( strcmp(inFlavor, "image/jpeg") == 0 ) {
301 // I'd assume we don't want to do anything for binary data....
303 else {
304 PRUnichar* buffAsUnichar = reinterpret_cast<PRUnichar*>(*ioData);
305 PRUnichar* oldBuffer = buffAsUnichar;
306 PRInt32 newLengthInChars;
307 retVal = nsLinebreakConverter::ConvertUnicharLineBreaksInSitu ( &buffAsUnichar, nsLinebreakConverter::eLinebreakAny,
308 nsLinebreakConverter::eLinebreakContent,
309 *ioLengthInBytes / sizeof(PRUnichar), &newLengthInChars );
310 if ( NS_SUCCEEDED(retVal) ) {
311 if ( buffAsUnichar != oldBuffer ) // check if buffer was reallocated
312 nsMemory::Free ( oldBuffer );
313 *ioData = buffAsUnichar;
314 *ioLengthInBytes = newLengthInChars * sizeof(PRUnichar);
318 return retVal;
320 } // ConvertPlatformToDOMLinebreaks