Bug 1487655 [wpt PR 12775] - [css-properties-values-api] Typify CSSStyleValue.parse...
[gecko.git] / widget / nsPrimitiveHelpers.cpp
blobf98ead28d6a6dd5777dd52d4776ed4bf34f17b73
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
8 //
9 // Part of the reason these routines are all in once place is so that as new
10 // data flavors are added that are known to be one-byte or two-byte strings, or even
11 // raw binary data, then we just have to go to one place to change how the data
12 // moves into/out of the primitives and native line endings.
14 // If you add new flavors that have special consideration (binary data or one-byte
15 // char* strings), please update all the helper classes in this file.
17 // For now, this is the assumption that we are making:
18 // - text/plain is always a char*
19 // - anything else is a char16_t*
23 #include "nsPrimitiveHelpers.h"
25 #include "mozilla/UniquePtr.h"
26 #include "nsCOMPtr.h"
27 #include "nsXPCOM.h"
28 #include "nsISupportsPrimitives.h"
29 #include "nsITransferable.h"
30 #include "nsIComponentManager.h"
31 #include "nsLinebreakConverter.h"
32 #include "nsReadableUtils.h"
36 // CreatePrimitiveForData
38 // Given some data and the flavor it corresponds to, creates the appropriate
39 // nsISupports* wrapper for passing across IDL boundaries. Right now, everything
40 // creates a two-byte |nsISupportsString|, except for "text/plain" and native
41 // platform HTML (CF_HTML on win32)
43 void
44 nsPrimitiveHelpers :: CreatePrimitiveForData ( const nsACString& aFlavor, const void* aDataBuff,
45 uint32_t aDataLen, nsISupports** aPrimitive )
47 if ( !aPrimitive )
48 return;
50 if ( aFlavor.EqualsLiteral(kTextMime) ||
51 aFlavor.EqualsLiteral(kNativeHTMLMime) ||
52 aFlavor.EqualsLiteral(kRTFMime) ||
53 aFlavor.EqualsLiteral(kCustomTypesMime)) {
54 nsCOMPtr<nsISupportsCString> primitive =
55 do_CreateInstance(NS_SUPPORTS_CSTRING_CONTRACTID);
56 if ( primitive ) {
57 const char * start = reinterpret_cast<const char*>(aDataBuff);
58 primitive->SetData(Substring(start, start + aDataLen));
59 NS_ADDREF(*aPrimitive = primitive);
62 else {
63 nsCOMPtr<nsISupportsString> primitive =
64 do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID);
65 if (primitive ) {
66 if (aDataLen % 2) {
67 auto buffer = mozilla::MakeUnique<char[]>(aDataLen + 1);
68 if (!MOZ_LIKELY(buffer))
69 return;
71 memcpy(buffer.get(), aDataBuff, aDataLen);
72 buffer[aDataLen] = 0;
73 const char16_t* start = reinterpret_cast<const char16_t*>(buffer.get());
74 // recall that length takes length as characters, not bytes
75 primitive->SetData(Substring(start, start + (aDataLen + 1) / 2));
76 } else {
77 const char16_t* start = reinterpret_cast<const char16_t*>(aDataBuff);
78 // recall that length takes length as characters, not bytes
79 primitive->SetData(Substring(start, start + (aDataLen / 2)));
81 NS_ADDREF(*aPrimitive = primitive);
85 } // CreatePrimitiveForData
88 // CreatePrimitiveForCFHTML
90 // Platform specific CreatePrimitive, windows CF_HTML.
92 void
93 nsPrimitiveHelpers :: CreatePrimitiveForCFHTML ( const void* aDataBuff,
94 uint32_t* aDataLen, nsISupports** aPrimitive )
96 if (!aPrimitive)
97 return;
99 nsCOMPtr<nsISupportsString> primitive =
100 do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID);
101 if (!primitive)
102 return;
104 // We need to duplicate the input buffer, since the removal of linebreaks
105 // might reallocte it.
106 void* utf8 = moz_xmalloc(*aDataLen);
107 memcpy(utf8, aDataBuff, *aDataLen);
108 int32_t signedLen = static_cast<int32_t>(*aDataLen);
109 nsLinebreakHelpers::ConvertPlatformToDOMLinebreaks(nsDependentCString(kTextMime), &utf8, &signedLen);
110 *aDataLen = signedLen;
112 nsAutoString str(NS_ConvertUTF8toUTF16(reinterpret_cast<const char*>(utf8), *aDataLen));
113 free(utf8);
114 *aDataLen = str.Length() * sizeof(char16_t);
115 primitive->SetData(str);
116 NS_ADDREF(*aPrimitive = primitive);
121 // CreateDataFromPrimitive
123 // Given a nsISupports* primitive and the flavor it represents, creates a new data
124 // buffer with the data in it. This data will be null terminated, but the length
125 // parameter does not reflect that.
127 void
128 nsPrimitiveHelpers :: CreateDataFromPrimitive ( const nsACString& aFlavor, nsISupports* aPrimitive,
129 void** aDataBuff, uint32_t aDataLen )
131 if ( !aDataBuff )
132 return;
134 *aDataBuff = nullptr;
136 if (aFlavor.EqualsLiteral(kTextMime) ||
137 aFlavor.EqualsLiteral(kCustomTypesMime)) {
138 nsCOMPtr<nsISupportsCString> plainText ( do_QueryInterface(aPrimitive) );
139 if ( plainText ) {
140 nsAutoCString data;
141 plainText->GetData ( data );
142 *aDataBuff = ToNewCString(data);
145 else {
146 nsCOMPtr<nsISupportsString> doubleByteText ( do_QueryInterface(aPrimitive) );
147 if ( doubleByteText ) {
148 nsAutoString data;
149 doubleByteText->GetData ( data );
150 *aDataBuff = ToNewUnicode(data);
158 // ConvertPlatformToDOMLinebreaks
160 // Given some data, convert from the platform linebreaks into the LF expected by the
161 // DOM. This will attempt to convert the data in place, but the buffer may still need to
162 // be reallocated regardless (disposing the old buffer is taken care of internally, see
163 // the note below).
165 // NOTE: this assumes that it can use 'free' to dispose of the old buffer.
167 nsresult
168 nsLinebreakHelpers :: ConvertPlatformToDOMLinebreaks ( const nsACString& inFlavor, void** ioData,
169 int32_t* ioLengthInBytes )
171 NS_ASSERTION ( ioData && *ioData && ioLengthInBytes, "Bad Params");
172 if ( !(ioData && *ioData && ioLengthInBytes) )
173 return NS_ERROR_INVALID_ARG;
175 nsresult retVal = NS_OK;
177 if (inFlavor.EqualsLiteral(kTextMime) ||
178 inFlavor.EqualsLiteral(kRTFMime)) {
179 char* buffAsChars = reinterpret_cast<char*>(*ioData);
180 char* oldBuffer = buffAsChars;
181 retVal = nsLinebreakConverter::ConvertLineBreaksInSitu ( &buffAsChars, nsLinebreakConverter::eLinebreakAny,
182 nsLinebreakConverter::eLinebreakContent,
183 *ioLengthInBytes, ioLengthInBytes );
184 if ( NS_SUCCEEDED(retVal) ) {
185 if ( buffAsChars != oldBuffer ) // check if buffer was reallocated
186 free ( oldBuffer );
187 *ioData = buffAsChars;
190 else if (inFlavor.EqualsLiteral("image/jpeg")) {
191 // I'd assume we don't want to do anything for binary data....
193 else {
194 char16_t* buffAsUnichar = reinterpret_cast<char16_t*>(*ioData);
195 char16_t* oldBuffer = buffAsUnichar;
196 int32_t newLengthInChars;
197 retVal = nsLinebreakConverter::ConvertUnicharLineBreaksInSitu ( &buffAsUnichar, nsLinebreakConverter::eLinebreakAny,
198 nsLinebreakConverter::eLinebreakContent,
199 *ioLengthInBytes / sizeof(char16_t), &newLengthInChars );
200 if ( NS_SUCCEEDED(retVal) ) {
201 if ( buffAsUnichar != oldBuffer ) // check if buffer was reallocated
202 free ( oldBuffer );
203 *ioData = buffAsUnichar;
204 *ioLengthInBytes = newLengthInChars * sizeof(char16_t);
208 return retVal;
210 } // ConvertPlatformToDOMLinebreaks