void LayerManager::StopFrameTimeRecording(uint32_t aStartIndex, nsTArray<float>& aFrameIntervals, nsTArray<float>& aPaintTimes) { uint32_t bufferSize = mRecording.mIntervals.Length(); uint32_t length = mRecording.mNextIndex - aStartIndex; if (mRecording.mIsPaused || length > bufferSize || aStartIndex < mRecording.mCurrentRunStartIndex) { // aStartIndex is too old. Also if aStartIndex was issued before mRecordingNextIndex overflowed (uint32_t) // and stopped after the overflow (would happen once every 828 days of constant 60fps). length = 0; } // Set length in advance to avoid possibly repeated reallocations (and OOM checks). if (!length || !aFrameIntervals.SetLength(length) || !aPaintTimes.SetLength(length)) { aFrameIntervals.Clear(); aPaintTimes.Clear(); return; // empty recording or OOM, return empty arrays. } uint32_t cyclicPos = aStartIndex % bufferSize; for (uint32_t i = 0; i < length; i++, cyclicPos++) { if (cyclicPos == bufferSize) { cyclicPos = 0; } aFrameIntervals[i] = mRecording.mIntervals[cyclicPos]; aPaintTimes[i] = mRecording.mPaints[cyclicPos]; } }
bool DWriteFontFileStream::Initialize(uint8_t* aData, uint32_t aSize) { if (!mData.SetLength(aSize, fallible)) { return false; } memcpy(mData.Elements(), aData, aSize); return true; }
bool ReadIntoArray(nsIFile* aFile, nsTArray<uint8_t>& aOutDst, size_t aMaxLength) { if (!FileExists(aFile)) { return false; } PRFileDesc* fd = nullptr; nsresult rv = aFile->OpenNSPRFileDesc(PR_RDONLY, 0, &fd); if (NS_FAILED(rv)) { return false; } int32_t length = PR_Seek(fd, 0, PR_SEEK_END); PR_Seek(fd, 0, PR_SEEK_SET); if (length < 0 || (size_t)length > aMaxLength) { NS_WARNING("EME file is longer than maximum allowed length"); PR_Close(fd); return false; } aOutDst.SetLength(length); int32_t bytesRead = PR_Read(fd, aOutDst.Elements(), length); PR_Close(fd); return (bytesRead == length); }
// add a continuation, return false on error if segment already has been seen bool addContinuation(nsTArray<Continuation>& aArray, uint32_t aIndex, const char *aValue, uint32_t aLength, bool aNeedsPercentDecoding, bool aWasQuotedString) { if (aIndex < aArray.Length() && aArray[aIndex].value) { NS_WARNING("duplicate RC2231 continuation segment #\n"); return false; } if (aIndex > MAX_CONTINUATIONS) { NS_WARNING("RC2231 continuation segment # exceeds limit\n"); return false; } if (aNeedsPercentDecoding && aWasQuotedString) { NS_WARNING("RC2231 continuation segment can't use percent encoding and quoted string form at the same time\n"); return false; } Continuation cont(aValue, aLength, aNeedsPercentDecoding, aWasQuotedString); if (aArray.Length() <= aIndex) { aArray.SetLength(aIndex + 1); } aArray[aIndex] = cont; return true; }
// Getter for weighted regions: { top, bottom, left, right, weight } nsresult nsDOMCameraControl::Get(uint32_t aKey, nsTArray<CameraRegion>& aValue) { nsTArray<ICameraControl::Region> regionArray; nsresult rv = mCameraControl->Get(aKey, regionArray); NS_ENSURE_SUCCESS(rv, rv); uint32_t length = regionArray.Length(); DOM_CAMERA_LOGI("%s:%d : got %d regions\n", __func__, __LINE__, length); aValue.SetLength(length); for (uint32_t i = 0; i < length; ++i) { ICameraControl::Region& r = regionArray[i]; CameraRegion& v = aValue[i]; v.mTop = r.top; v.mLeft = r.left; v.mBottom = r.bottom; v.mRight = r.right; v.mWeight = r.weight; DOM_CAMERA_LOGI("region %d: top=%d, left=%d, bottom=%d, right=%d, weight=%u\n", i, v.mTop, v.mLeft, v.mBottom, v.mRight, v.mWeight ); } return NS_OK; }
void nsSVGTextContainerFrame::CopyPositionList(nsTArray<float> *parentList, SVGUserUnitList *selfList, nsTArray<float> &dstList, uint32_t aOffset) { dstList.Clear(); uint32_t strLength = GetNumberOfChars(); uint32_t parentCount = 0; if (parentList && parentList->Length() > aOffset) { parentCount = NS_MIN(parentList->Length() - aOffset, strLength); } uint32_t selfCount = NS_MIN(selfList->Length(), strLength); uint32_t count = NS_MAX(parentCount, selfCount); if (!dstList.SetLength(count)) return; for (uint32_t i = 0; i < selfCount; i++) { dstList[i] = (*selfList)[i]; } for (uint32_t i = selfCount; i < parentCount; i++) { dstList[i] = (*parentList)[aOffset + i]; } }
void nsSVGTextContainerFrame::CopyRotateList(nsTArray<float> *parentList, const SVGNumberList *selfList, nsTArray<float> &dstList, uint32_t aOffset) { dstList.Clear(); uint32_t strLength = GetNumberOfChars(); uint32_t parentCount = 0; if (parentList && parentList->Length() > aOffset) { parentCount = NS_MIN(parentList->Length() - aOffset, strLength); } uint32_t selfCount = NS_MIN(selfList ? selfList->Length() : 0, strLength); uint32_t count = NS_MAX(parentCount, selfCount); if (count > 0) { if (!dstList.SetLength(count)) return; for (uint32_t i = 0; i < selfCount; i++) { dstList[i] = (*selfList)[i]; } for (uint32_t i = selfCount; i < parentCount; i++) { dstList[i] = (*parentList)[aOffset + i]; } } else if (parentList && !parentList->IsEmpty()) { // rotate is applied to extra characters too dstList.AppendElement((*parentList)[parentList->Length() - 1]); } }
void detail::DoConversion(const nsTArray<nsString> &aUTF16Array, nsTArray<nsCString> &aUTF8Array) { uint32_t count = aUTF16Array.Length(); aUTF8Array.SetLength(count); for (uint32_t i = 0; i < count; ++i) CopyUTF16toUTF8(aUTF16Array[i], aUTF8Array[i]); }
nsresult GDIFontEntry::CopyFontTable(uint32_t aTableTag, nsTArray<uint8_t>& aBuffer) { if (!IsTrueType()) { return NS_ERROR_FAILURE; } AutoDC dc; AutoSelectFont font(dc.GetDC(), &mLogFont); if (font.IsValid()) { uint32_t tableSize = ::GetFontData(dc.GetDC(), NativeEndian::swapToBigEndian(aTableTag), 0, nullptr, 0); if (tableSize != GDI_ERROR) { if (aBuffer.SetLength(tableSize, fallible)) { ::GetFontData(dc.GetDC(), NativeEndian::swapToBigEndian(aTableTag), 0, aBuffer.Elements(), tableSize); return NS_OK; } return NS_ERROR_OUT_OF_MEMORY; } } return NS_ERROR_FAILURE; }
GMPErr Read(const nsCString& aRecordName, nsTArray<uint8_t>& aOutBytes) override { if (!IsOpen(aRecordName)) { return GMPClosedErr; } Record* record = nullptr; mRecords.Get(aRecordName, &record); MOZ_ASSERT(record && !!record->mFileDesc); // IsOpen() guarantees this. // Our error strategy is to report records with invalid contents as // containing 0 bytes. Zero length records are considered "deleted" by // the GMPStorage API. aOutBytes.SetLength(0); int32_t recordLength = 0; nsCString recordName; nsresult err = ReadRecordMetadata(record->mFileDesc, recordLength, recordName); if (NS_FAILED(err) || recordLength == 0) { // We failed to read the record metadata. Or the record is 0 length. // Treat damaged records as empty. // ReadRecordMetadata() could fail if the GMP opened a new record and // tried to read it before anything was written to it.. return GMPNoErr; } if (!aRecordName.Equals(recordName)) { NS_WARNING("Record file contains some other record's contents!"); return GMPRecordCorrupted; } // After calling ReadRecordMetadata, we should be ready to read the // record data. if (PR_Available(record->mFileDesc) != recordLength) { NS_WARNING("Record file length mismatch!"); return GMPRecordCorrupted; } aOutBytes.SetLength(recordLength); int32_t bytesRead = PR_Read(record->mFileDesc, aOutBytes.Elements(), recordLength); return (bytesRead == recordLength) ? GMPNoErr : GMPRecordCorrupted; }
void ExtractDisplayAddresses(const nsCOMArray<msgIAddressObject> &aHeader, nsTArray<nsString> &displayAddrs) { uint32_t count = aHeader.Length(); displayAddrs.SetLength(count); for (uint32_t i = 0; i < count; i++) aHeader[i]->ToString(displayAddrs[i]); if (count == 1 && displayAddrs[0].IsEmpty()) displayAddrs.Clear(); }
/* static */ bool PushUtil::CopyArrayBufferToArray(const ArrayBuffer& aBuffer, nsTArray<uint8_t>& aArray) { aBuffer.ComputeLengthAndData(); return aArray.SetLength(aBuffer.Length(), fallible) && aArray.ReplaceElementsAt(0, aBuffer.Length(), aBuffer.Data(), aBuffer.Length(), fallible); }
void AudioNodeStream::UpMixDownMixChunk(const AudioChunk* aChunk, uint32_t aOutputChannelCount, nsTArray<const void*>& aOutputChannels, nsTArray<float>& aDownmixBuffer) { static const float silenceChannel[WEBAUDIO_BLOCK_SIZE] = {0.f}; aOutputChannels.AppendElements(aChunk->mChannelData); if (aOutputChannels.Length() < aOutputChannelCount) { if (mChannelInterpretation == ChannelInterpretation::Speakers) { AudioChannelsUpMix(&aOutputChannels, aOutputChannelCount, nullptr); NS_ASSERTION(aOutputChannelCount == aOutputChannels.Length(), "We called GetAudioChannelsSuperset to avoid this"); } else { // Fill up the remaining aOutputChannels by zeros for (uint32_t j = aOutputChannels.Length(); j < aOutputChannelCount; ++j) { aOutputChannels.AppendElement(silenceChannel); } } } else if (aOutputChannels.Length() > aOutputChannelCount) { if (mChannelInterpretation == ChannelInterpretation::Speakers) { nsAutoTArray<float*,GUESS_AUDIO_CHANNELS> outputChannels; outputChannels.SetLength(aOutputChannelCount); aDownmixBuffer.SetLength(aOutputChannelCount * WEBAUDIO_BLOCK_SIZE); for (uint32_t j = 0; j < aOutputChannelCount; ++j) { outputChannels[j] = &aDownmixBuffer[j * WEBAUDIO_BLOCK_SIZE]; } AudioChannelsDownMix(aOutputChannels, outputChannels.Elements(), aOutputChannelCount, WEBAUDIO_BLOCK_SIZE); aOutputChannels.SetLength(aOutputChannelCount); for (uint32_t j = 0; j < aOutputChannels.Length(); ++j) { aOutputChannels[j] = outputChannels[j]; } } else { // Drop the remaining aOutputChannels aOutputChannels.RemoveElementsAt(aOutputChannelCount, aOutputChannels.Length() - aOutputChannelCount); } } }
void ExtractAllAddresses(const nsCOMArray<msgIAddressObject> &aHeader, nsTArray<nsString> &names, nsTArray<nsString> &emails) { uint32_t count = aHeader.Length(); // Prefill arrays before we start names.SetLength(count); emails.SetLength(count); for (uint32_t i = 0; i < count; i++) { aHeader[i]->GetName(names[i]); aHeader[i]->GetEmail(emails[i]); } if (count == 1 && names[0].IsEmpty() && emails[0].IsEmpty()) { names.Clear(); emails.Clear(); } }
bool GetPreparsedData(HANDLE handle, nsTArray<uint8_t>& data) { UINT size; if (GetRawInputDeviceInfo(handle, RIDI_PREPARSEDDATA, nullptr, &size) == kRawInputError) { return false; } data.SetLength(size); return GetRawInputDeviceInfo(handle, RIDI_PREPARSEDDATA, data.Elements(), &size) > 0; }
void nsGridContainerFrame::CalculateTrackSizes(const LogicalSize& aPercentageBasis, const nsStylePosition* aStyle, nsTArray<TrackSize>& aColSizes, nsTArray<TrackSize>& aRowSizes) { aColSizes.SetLength(mGridColEnd - 1); aRowSizes.SetLength(mGridRowEnd - 1); WritingMode wm = GetWritingMode(); InitializeTrackSizes(aPercentageBasis.ISize(wm), aStyle->mGridTemplateColumns.mMinTrackSizingFunctions, aStyle->mGridTemplateColumns.mMaxTrackSizingFunctions, aStyle->mGridAutoColumnsMin, aStyle->mGridAutoColumnsMax, aColSizes); InitializeTrackSizes(aPercentageBasis.BSize(wm), aStyle->mGridTemplateRows.mMinTrackSizingFunctions, aStyle->mGridTemplateRows.mMaxTrackSizingFunctions, aStyle->mGridAutoRowsMin, aStyle->mGridAutoRowsMax, aRowSizes); }
void nsProfileCollector::BookmarkCounter::CountChildren(PRInt64 root, PRBool deep, nsTArray<PRInt32> &count) { count.SetLength(kLastBookmarkType); for (PRInt32 i = 0; i < kLastBookmarkType; ++i) { count[i] = 0; } nsCOMPtr<nsINavHistoryService> histSvc = do_GetService(NS_NAVHISTORYSERVICE_CONTRACTID); if (!histSvc) { return; } nsCOMPtr<nsINavHistoryQuery> query; histSvc->GetNewQuery(getter_AddRefs(query)); if (!query) { return; } query->SetFolders(&root, 1); query->SetOnlyBookmarked(PR_TRUE); nsCOMPtr<nsINavHistoryQueryOptions> options; histSvc->GetNewQueryOptions(getter_AddRefs(options)); if (!options) { return; } // setting option breaks bookmark count // const PRUint16 groupMode = nsINavHistoryQueryOptions::GROUP_BY_FOLDER; // options->SetGroupingMode(&groupMode, 1); nsCOMPtr<nsINavHistoryResult> result; histSvc->ExecuteQuery(query, options, getter_AddRefs(result)); if (!result) { return; } nsCOMPtr<nsINavHistoryContainerResultNode> rootNode; result->GetRoot(getter_AddRefs(rootNode)); if (!rootNode) { return; } CountRecursive(rootNode, deep, count); }
/* static */ bool PushUtil::CopyBufferSourceToArray( const OwningArrayBufferViewOrArrayBuffer& aSource, nsTArray<uint8_t>& aArray) { if (aSource.IsArrayBuffer()) { return CopyArrayBufferToArray(aSource.GetAsArrayBuffer(), aArray); } if (aSource.IsArrayBufferView()) { const ArrayBufferView& view = aSource.GetAsArrayBufferView(); view.ComputeLengthAndData(); return aArray.SetLength(view.Length(), fallible) && aArray.ReplaceElementsAt(0, view.Length(), view.Data(), view.Length(), fallible); } MOZ_CRASH("Uninitialized union: expected buffer or view"); }
nsresult ICameraControl::GetListOfCameras(nsTArray<nsString>& aList) { int32_t count = android::Camera::getNumberOfCameras(); DOM_CAMERA_LOGI("getListOfCameras : getNumberOfCameras() returned %d\n", count); if (count <= 0) { aList.Clear(); return NS_OK; } // Allocate 2 extra slots to reserve space for 'front' and 'back' cameras // at the front of the array--we will collapse any empty slots below. aList.SetLength(2); uint32_t extraIdx = 2; bool gotFront = false; bool gotBack = false; while (count--) { nsCString cameraName; nsresult result = GetCameraName(count, cameraName); if (result != NS_OK) { continue; } // The first camera we find named 'back' gets slot 0; and the first // we find named 'front' gets slot 1. All others appear after these. if (cameraName.EqualsLiteral("back")) { CopyUTF8toUTF16(cameraName, aList[0]); gotBack = true; } else if (cameraName.EqualsLiteral("front")) { CopyUTF8toUTF16(cameraName, aList[1]); gotFront = true; } else { CopyUTF8toUTF16(cameraName, *aList.InsertElementAt(extraIdx)); extraIdx++; } } if (!gotFront) { aList.RemoveElementAt(1); } if (!gotBack) { aList.RemoveElementAt(0); } return NS_OK; }
static void BlacklistEntriesToDriverInfo(nsTArray<nsCString>& aBlacklistEntries, nsTArray<GfxDriverInfo>& aDriverInfo) { aDriverInfo.Clear(); aDriverInfo.SetLength(aBlacklistEntries.Length()); for (uint32_t i = 0; i < aBlacklistEntries.Length(); ++i) { nsCString blacklistEntry = aBlacklistEntries[i]; GfxDriverInfo di; if (BlacklistEntryToDriverInfo(blacklistEntry, di)) { aDriverInfo[i] = di; // Prevent di falling out of scope from destroying the devices. di.mDeleteDevices = false; } } }
void InternalHeaders::GetAll(const nsACString& aName, nsTArray<nsCString>& aResults, ErrorResult& aRv) const { nsAutoCString lowerName; ToLowerCase(aName, lowerName); if (IsInvalidName(lowerName, aRv)) { return; } aResults.SetLength(0); for (uint32_t i = 0; i < mList.Length(); ++i) { if (lowerName == mList[i].mName) { aResults.AppendElement(mList[i].mValue); } } }
static void ReadFile(const char* aPath, nsTArray<uint8_t>& aBuffer) { FILE* f = fopen(aPath, "rb"); ASSERT_NE(f, (FILE*)nullptr); int r = fseek(f, 0, SEEK_END); ASSERT_EQ(r, 0); long size = ftell(f); ASSERT_NE(size, -1); aBuffer.SetLength(size); r = fseek(f, 0, SEEK_SET); ASSERT_EQ(r, 0); size_t got = fread(aBuffer.Elements(), 1, size, f); ASSERT_EQ(got, size_t(size)); r = fclose(f); ASSERT_EQ(r, 0); }
static void BlacklistEntriesToDriverInfo(nsIDOMHTMLCollection* aBlacklistEntries, nsTArray<GfxDriverInfo>& aDriverInfo) { uint32_t length; if (NS_FAILED(aBlacklistEntries->GetLength(&length))) return; aDriverInfo.Clear(); aDriverInfo.SetLength(length); for (uint32_t i = 0; i < length; ++i) { nsCOMPtr<nsIDOMNode> blacklistEntry; if (NS_SUCCEEDED(aBlacklistEntries->Item(i, getter_AddRefs(blacklistEntry))) && blacklistEntry) { GfxDriverInfo di; if (BlacklistEntryToDriverInfo(blacklistEntry, di)) { aDriverInfo[i] = di; // Prevent di falling out of scope from destroying the devices. di.mDeleteDevices = false; } } } }
bool nsCaseTransformTextRunFactory::TransformString( const nsAString& aString, nsString& aConvertedString, bool aAllUppercase, const nsIAtom* aLanguage, nsTArray<bool>& aCharsToMergeArray, nsTArray<bool>& aDeletedCharsArray, nsTransformedTextRun* aTextRun, nsTArray<uint8_t>* aCanBreakBeforeArray, nsTArray<nsStyleContext*>* aStyleArray) { NS_PRECONDITION(!aTextRun || (aCanBreakBeforeArray && aStyleArray), "either none or all three optional parameters required"); uint32_t length = aString.Length(); const char16_t* str = aString.BeginReading(); bool mergeNeeded = false; bool capitalizeDutchIJ = false; bool prevIsLetter = false; bool ntPrefix = false; // true immediately after a word-initial 'n' or 't' // when doing Irish lowercasing uint32_t sigmaIndex = uint32_t(-1); nsIUGenCategory::nsUGenCategory cat; uint8_t style = aAllUppercase ? NS_STYLE_TEXT_TRANSFORM_UPPERCASE : 0; const nsIAtom* lang = aLanguage; LanguageSpecificCasingBehavior languageSpecificCasing = GetCasingFor(lang); mozilla::GreekCasing::State greekState; mozilla::IrishCasing::State irishState; uint32_t irishMark = uint32_t(-1); // location of possible prefix letter(s) for (uint32_t i = 0; i < length; ++i) { uint32_t ch = str[i]; nsStyleContext* styleContext; if (aTextRun) { styleContext = aTextRun->mStyles[i]; style = aAllUppercase ? NS_STYLE_TEXT_TRANSFORM_UPPERCASE : styleContext->StyleText()->mTextTransform; if (lang != styleContext->StyleFont()->mLanguage) { lang = styleContext->StyleFont()->mLanguage; languageSpecificCasing = GetCasingFor(lang); greekState.Reset(); irishState.Reset(); irishMark = uint32_t(-1); } } int extraChars = 0; const mozilla::unicode::MultiCharMapping *mcm; bool inhibitBreakBefore = false; // have we just deleted preceding hyphen? if (NS_IS_HIGH_SURROGATE(ch) && i < length - 1 && NS_IS_LOW_SURROGATE(str[i + 1])) { ch = SURROGATE_TO_UCS4(ch, str[i + 1]); } switch (style) { case NS_STYLE_TEXT_TRANSFORM_LOWERCASE: if (languageSpecificCasing == eLSCB_Turkish) { if (ch == 'I') { ch = LATIN_SMALL_LETTER_DOTLESS_I; prevIsLetter = true; sigmaIndex = uint32_t(-1); break; } if (ch == LATIN_CAPITAL_LETTER_I_WITH_DOT_ABOVE) { ch = 'i'; prevIsLetter = true; sigmaIndex = uint32_t(-1); break; } } cat = mozilla::unicode::GetGenCategory(ch); if (languageSpecificCasing == eLSCB_Irish && cat == nsIUGenCategory::kLetter) { // See bug 1018805 for Irish lowercasing requirements if (!prevIsLetter && (ch == 'n' || ch == 't')) { ntPrefix = true; } else { if (ntPrefix && mozilla::IrishCasing::IsUpperVowel(ch)) { aConvertedString.Append('-'); ++extraChars; } ntPrefix = false; } } else { ntPrefix = false; } // Special lowercasing behavior for Greek Sigma: note that this is listed // as context-sensitive in Unicode's SpecialCasing.txt, but is *not* a // language-specific mapping; it applies regardless of the language of // the element. // // The lowercase mapping for CAPITAL SIGMA should be to SMALL SIGMA (i.e. // the non-final form) whenever there is a following letter, or when the // CAPITAL SIGMA occurs in isolation (neither preceded nor followed by a // LETTER); and to FINAL SIGMA when it is preceded by another letter but // not followed by one. // // To implement the context-sensitive nature of this mapping, we keep // track of whether the previous character was a letter. If not, CAPITAL // SIGMA will map directly to SMALL SIGMA. If the previous character // was a letter, CAPITAL SIGMA maps to FINAL SIGMA and we record the // position in the converted string; if we then encounter another letter, // that FINAL SIGMA is replaced with a standard SMALL SIGMA. // If sigmaIndex is not -1, it marks where we have provisionally mapped // a CAPITAL SIGMA to FINAL SIGMA; if we now find another letter, we // need to change it to SMALL SIGMA. if (sigmaIndex != uint32_t(-1)) { if (cat == nsIUGenCategory::kLetter) { aConvertedString.SetCharAt(GREEK_SMALL_LETTER_SIGMA, sigmaIndex); } } if (ch == GREEK_CAPITAL_LETTER_SIGMA) { // If preceding char was a letter, map to FINAL instead of SMALL, // and note where it occurred by setting sigmaIndex; we'll change it // to standard SMALL SIGMA later if another letter follows if (prevIsLetter) { ch = GREEK_SMALL_LETTER_FINAL_SIGMA; sigmaIndex = aConvertedString.Length(); } else { // CAPITAL SIGMA not preceded by a letter is unconditionally mapped // to SMALL SIGMA ch = GREEK_SMALL_LETTER_SIGMA; sigmaIndex = uint32_t(-1); } prevIsLetter = true; break; } // ignore diacritics for the purpose of contextual sigma mapping; // otherwise, reset prevIsLetter appropriately and clear the // sigmaIndex marker if (cat != nsIUGenCategory::kMark) { prevIsLetter = (cat == nsIUGenCategory::kLetter); sigmaIndex = uint32_t(-1); } mcm = mozilla::unicode::SpecialLower(ch); if (mcm) { int j = 0; while (j < 2 && mcm->mMappedChars[j + 1]) { aConvertedString.Append(mcm->mMappedChars[j]); ++extraChars; ++j; } ch = mcm->mMappedChars[j]; break; } ch = ToLowerCase(ch); break; case NS_STYLE_TEXT_TRANSFORM_UPPERCASE: if (languageSpecificCasing == eLSCB_Turkish && ch == 'i') { ch = LATIN_CAPITAL_LETTER_I_WITH_DOT_ABOVE; break; } if (languageSpecificCasing == eLSCB_Greek) { ch = mozilla::GreekCasing::UpperCase(ch, greekState); break; } if (languageSpecificCasing == eLSCB_Irish) { bool mark; uint8_t action; ch = mozilla::IrishCasing::UpperCase(ch, irishState, mark, action); if (mark) { irishMark = aConvertedString.Length(); break; } else if (action) { nsString& str = aConvertedString; // shorthand switch (action) { case 1: // lowercase a single prefix letter NS_ASSERTION(str.Length() > 0 && irishMark < str.Length(), "bad irishMark!"); str.SetCharAt(ToLowerCase(str[irishMark]), irishMark); irishMark = uint32_t(-1); break; case 2: // lowercase two prefix letters (immediately before current pos) NS_ASSERTION(str.Length() >= 2 && irishMark == str.Length() - 2, "bad irishMark!"); str.SetCharAt(ToLowerCase(str[irishMark]), irishMark); str.SetCharAt(ToLowerCase(str[irishMark + 1]), irishMark + 1); irishMark = uint32_t(-1); break; case 3: // lowercase one prefix letter, and delete following hyphen // (which must be the immediately-preceding char) NS_ASSERTION(str.Length() >= 2 && irishMark == str.Length() - 2, "bad irishMark!"); str.Replace(irishMark, 2, ToLowerCase(str[irishMark])); aDeletedCharsArray[irishMark + 1] = true; // Remove the trailing entries (corresponding to the deleted hyphen) // from the auxiliary arrays. aCharsToMergeArray.SetLength(aCharsToMergeArray.Length() - 1); if (aTextRun) { aStyleArray->SetLength(aStyleArray->Length() - 1); aCanBreakBeforeArray->SetLength(aCanBreakBeforeArray->Length() - 1); inhibitBreakBefore = true; } mergeNeeded = true; irishMark = uint32_t(-1); break; } // ch has been set to the uppercase for current char; // No need to check for SpecialUpper here as none of the characters // that could trigger an Irish casing action have special mappings. break; } // If we didn't have any special action to perform, fall through // to check for special uppercase (ß) } mcm = mozilla::unicode::SpecialUpper(ch); if (mcm) { int j = 0; while (j < 2 && mcm->mMappedChars[j + 1]) { aConvertedString.Append(mcm->mMappedChars[j]); ++extraChars; ++j; } ch = mcm->mMappedChars[j]; break; } ch = ToUpperCase(ch); break; case NS_STYLE_TEXT_TRANSFORM_CAPITALIZE: if (aTextRun) { if (capitalizeDutchIJ && ch == 'j') { ch = 'J'; capitalizeDutchIJ = false; break; } capitalizeDutchIJ = false; if (i < aTextRun->mCapitalize.Length() && aTextRun->mCapitalize[i]) { if (languageSpecificCasing == eLSCB_Turkish && ch == 'i') { ch = LATIN_CAPITAL_LETTER_I_WITH_DOT_ABOVE; break; } if (languageSpecificCasing == eLSCB_Dutch && ch == 'i') { ch = 'I'; capitalizeDutchIJ = true; break; } mcm = mozilla::unicode::SpecialTitle(ch); if (mcm) { int j = 0; while (j < 2 && mcm->mMappedChars[j + 1]) { aConvertedString.Append(mcm->mMappedChars[j]); ++extraChars; ++j; } ch = mcm->mMappedChars[j]; break; } ch = ToTitleCase(ch); } } break; case NS_STYLE_TEXT_TRANSFORM_FULLWIDTH: ch = mozilla::unicode::GetFullWidth(ch); break; default: break; } if (ch == uint32_t(-1)) { aDeletedCharsArray.AppendElement(true); mergeNeeded = true; } else { aDeletedCharsArray.AppendElement(false); aCharsToMergeArray.AppendElement(false); if (aTextRun) { aStyleArray->AppendElement(styleContext); aCanBreakBeforeArray->AppendElement(inhibitBreakBefore ? false : aTextRun->CanBreakLineBefore(i)); } if (IS_IN_BMP(ch)) { aConvertedString.Append(ch); } else { aConvertedString.Append(H_SURROGATE(ch)); aConvertedString.Append(L_SURROGATE(ch)); ++i; aDeletedCharsArray.AppendElement(true); // not exactly deleted, but the // trailing surrogate is skipped ++extraChars; } while (extraChars-- > 0) { mergeNeeded = true; aCharsToMergeArray.AppendElement(true); if (aTextRun) { aStyleArray->AppendElement(styleContext); aCanBreakBeforeArray->AppendElement(false); } } } } return mergeNeeded; }
nsresult nsHyphenator::Hyphenate(const nsAString& aString, nsTArray<bool>& aHyphens) { if (!aHyphens.SetLength(aString.Length())) { return NS_ERROR_OUT_OF_MEMORY; } memset(aHyphens.Elements(), false, aHyphens.Length()); bool inWord = false; uint32_t wordStart = 0, wordLimit = 0; uint32_t chLen; for (uint32_t i = 0; i < aString.Length(); i += chLen) { uint32_t ch = aString[i]; chLen = 1; if (NS_IS_HIGH_SURROGATE(ch)) { if (i + 1 < aString.Length() && NS_IS_LOW_SURROGATE(aString[i+1])) { ch = SURROGATE_TO_UCS4(ch, aString[i+1]); chLen = 2; } else { NS_WARNING("unpaired surrogate found during hyphenation"); } } nsIUGenCategory::nsUGenCategory cat = mozilla::unicode::GetGenCategory(ch); if (cat == nsIUGenCategory::kLetter || cat == nsIUGenCategory::kMark) { if (!inWord) { inWord = true; wordStart = i; } wordLimit = i + chLen; if (i + chLen < aString.Length()) { continue; } } if (inWord) { const PRUnichar *begin = aString.BeginReading(); NS_ConvertUTF16toUTF8 utf8(begin + wordStart, wordLimit - wordStart); nsAutoTArray<char,200> utf8hyphens; utf8hyphens.SetLength(utf8.Length() + 5); char **rep = nullptr; int *pos = nullptr; int *cut = nullptr; int err = hnj_hyphen_hyphenate2((HyphenDict*)mDict, utf8.BeginReading(), utf8.Length(), utf8hyphens.Elements(), nullptr, &rep, &pos, &cut); if (!err) { // Surprisingly, hnj_hyphen_hyphenate2 converts the 'hyphens' buffer // from utf8 code unit indexing (which would match the utf8 input // string directly) to Unicode character indexing. // We then need to convert this to utf16 code unit offsets for Gecko. const char *hyphPtr = utf8hyphens.Elements(); const PRUnichar *cur = begin + wordStart; const PRUnichar *end = begin + wordLimit; while (cur < end) { if (*hyphPtr & 0x01) { aHyphens[cur - begin] = true; } cur++; if (cur < end && NS_IS_LOW_SURROGATE(*cur) && NS_IS_HIGH_SURROGATE(*(cur-1))) { cur++; } hyphPtr++; } } } inWord = false; } return NS_OK; }
nsresult nsHyphenator::Hyphenate(const nsAString& aString, nsTArray<PRPackedBool>& aHyphens) { if (!aHyphens.SetLength(aString.Length())) { return NS_ERROR_OUT_OF_MEMORY; } memset(aHyphens.Elements(), PR_FALSE, aHyphens.Length()); PRBool inWord = PR_FALSE; PRUint32 wordStart = 0, wordLimit = 0; for (PRUint32 i = 0; i < aString.Length(); i++) { PRUnichar ch = aString[i]; nsIUGenCategory::nsUGenCategory cat = mCategories->Get(ch); if (cat == nsIUGenCategory::kLetter || cat == nsIUGenCategory::kMark) { if (!inWord) { inWord = PR_TRUE; wordStart = i; } wordLimit = i + 1; if (i < aString.Length() - 1) { continue; } } if (inWord) { NS_ConvertUTF16toUTF8 utf8(aString.BeginReading() + wordStart, wordLimit - wordStart); nsAutoTArray<char,200> utf8hyphens; utf8hyphens.SetLength(utf8.Length() + 5); char **rep = nsnull; int *pos = nsnull; int *cut = nsnull; int err = hnj_hyphen_hyphenate2((HyphenDict*)mDict, utf8.BeginReading(), utf8.Length(), utf8hyphens.Elements(), nsnull, &rep, &pos, &cut); if (!err) { PRUint32 utf16offset = wordStart; const char *cp = utf8.BeginReading(); while (cp < utf8.EndReading()) { if (UTF8traits::isASCII(*cp)) { // single-byte utf8 char cp++; utf16offset++; } else if (UTF8traits::is2byte(*cp)) { // 2-byte sequence cp += 2; utf16offset++; } else if (UTF8traits::is3byte(*cp)) { // 3-byte sequence cp += 3; utf16offset++; } else { // must be a 4-byte sequence (no need to check validity, // as this was just created with NS_ConvertUTF16toUTF8) NS_ASSERTION(UTF8traits::is4byte(*cp), "unexpected utf8 byte"); cp += 4; utf16offset += 2; } NS_ASSERTION(cp <= utf8.EndReading(), "incomplete utf8 string?"); NS_ASSERTION(utf16offset <= aString.Length(), "length mismatch?"); if (utf8hyphens[cp - utf8.BeginReading() - 1] & 0x01) { aHyphens[utf16offset - 1] = PR_TRUE; } } } } inWord = PR_FALSE; } return NS_OK; }