OSErr sourceStringOfAEDesc(ComponentInstance component, AEDesc* inDesc, AEDesc *outDesc) { OSErr err = noErr; OSAID script_id = kOSANullScript; CFAttributedStringRef source_text = NULL; err = OSACoerceFromDesc(component, inDesc, kOSAModeNull, &script_id); if (noErr != err) goto bail; err = OSACopySourceString(component, script_id, kOSAModeNull, &source_text); if (noErr != err) goto bail; CFStringRef plain_text = CFAttributedStringGetString(source_text); #if useLog CFShow(plain_text); #endif err = AEDescCreateWithCFString(plain_text, kCFStringEncodingUTF8, outDesc); bail: OSADispose(component, script_id); safeRelease(source_text); return err; }
void InbandTextTrackPrivateAVF::processCueAttributes(CFAttributedStringRef attributedString, StringBuilder& content, StringBuilder& settings) { // Some of the attributes we translate into per-cue WebVTT settings are are repeated on each part of an attributed string so only // process the first instance of each. enum AttributeFlags { Line = 1 << 0, Position = 1 << 1, Size = 1 << 2, Vertical = 1 << 3, Align = 1 << 4 }; unsigned processed = 0; String attributedStringValue = CFAttributedStringGetString(attributedString); CFIndex length = attributedStringValue.length(); if (!length) return; CFRange effectiveRange = CFRangeMake(0, 0); while ((effectiveRange.location + effectiveRange.length) < length) { CFDictionaryRef attributes = CFAttributedStringGetAttributes(attributedString, effectiveRange.location + effectiveRange.length, &effectiveRange); if (!attributes) continue; StringBuilder tagStart; String tagEnd; CFIndex attributeCount = CFDictionaryGetCount(attributes); Vector<const void*> keys(attributeCount); Vector<const void*> values(attributeCount); CFDictionaryGetKeysAndValues(attributes, keys.data(), values.data()); for (CFIndex i = 0; i < attributeCount; ++i) { CFStringRef key = static_cast<CFStringRef>(keys[i]); CFTypeRef value = values[i]; if (CFGetTypeID(key) != CFStringGetTypeID() || !CFStringGetLength(key)) continue; if (CFStringCompare(key, kCMTextMarkupAttribute_Alignment, 0) == kCFCompareEqualTo) { CFStringRef valueString = static_cast<CFStringRef>(value); if (CFGetTypeID(valueString) != CFStringGetTypeID() || !CFStringGetLength(valueString)) continue; if (processed & Align) continue; processed |= Align; if (CFStringCompare(valueString, kCMTextMarkupAlignmentType_Start, 0) == kCFCompareEqualTo) settings.append("align:start "); else if (CFStringCompare(valueString, kCMTextMarkupAlignmentType_Middle, 0) == kCFCompareEqualTo) settings.append("align:middle "); else if (CFStringCompare(valueString, kCMTextMarkupAlignmentType_End, 0) == kCFCompareEqualTo) settings.append("align:end "); else ASSERT_NOT_REACHED(); continue; } if (CFStringCompare(key, kCMTextMarkupAttribute_BoldStyle, 0) == kCFCompareEqualTo) { if (static_cast<CFBooleanRef>(value) != kCFBooleanTrue) continue; tagStart.append("<b>"); tagEnd.insert("</b>", 0); continue; } if (CFStringCompare(key, kCMTextMarkupAttribute_ItalicStyle, 0) == kCFCompareEqualTo) { if (static_cast<CFBooleanRef>(value) != kCFBooleanTrue) continue; tagStart.append("<i>"); tagEnd.insert("</i>", 0); continue; } if (CFStringCompare(key, kCMTextMarkupAttribute_UnderlineStyle, 0) == kCFCompareEqualTo) { if (static_cast<CFBooleanRef>(value) != kCFBooleanTrue) continue; tagStart.append("<u>"); tagEnd.insert("</u>", 0); continue; } if (CFStringCompare(key, kCMTextMarkupAttribute_OrthogonalLinePositionPercentageRelativeToWritingDirection, 0) == kCFCompareEqualTo) { // Ignore the line position if the attributes also specify "size" so we keep WebVTT's default line logic if (CFDictionaryGetValue(attributes, kCMTextMarkupAttribute_WritingDirectionSizePercentage)) continue; if (CFGetTypeID(value) != CFNumberGetTypeID()) continue; if (processed & Line) continue; processed |= Line; CFNumberRef valueNumber = static_cast<CFNumberRef>(value); double position; CFNumberGetValue(valueNumber, kCFNumberFloat64Type, &position); settings.append(String::format("line:%ld%% ", lrint(position))); continue; } if (CFStringCompare(key, kCMTextMarkupAttribute_TextPositionPercentageRelativeToWritingDirection, 0) == kCFCompareEqualTo) { if (CFGetTypeID(value) != CFNumberGetTypeID()) continue; if (processed & Position) continue; processed |= Position; CFNumberRef valueNumber = static_cast<CFNumberRef>(value); double position; CFNumberGetValue(valueNumber, kCFNumberFloat64Type, &position); settings.append(String::format("position:%ld%% ", lrint(position))); continue; } if (CFStringCompare(key, kCMTextMarkupAttribute_WritingDirectionSizePercentage, 0) == kCFCompareEqualTo) { if (CFGetTypeID(value) != CFNumberGetTypeID()) continue; if (processed & Size) continue; processed |= Size; CFNumberRef valueNumber = static_cast<CFNumberRef>(value); double position; CFNumberGetValue(valueNumber, kCFNumberFloat64Type, &position); settings.append(String::format("size:%ld%% ", lrint(position))); continue; } } content.append(tagStart); content.append(attributedStringValue.substring(effectiveRange.location, effectiveRange.length)); content.append(tagEnd); } }
void InbandTextTrackPrivateAVF::processCueAttributes(CFAttributedStringRef attributedString, GenericCueData* cueData) { // Some of the attributes we translate into per-cue WebVTT settings are are repeated on each part of an attributed string so only // process the first instance of each. enum AttributeFlags { Line = 1 << 0, Position = 1 << 1, Size = 1 << 2, Vertical = 1 << 3, Align = 1 << 4, FontName = 1 << 5 }; unsigned processed = 0; StringBuilder content; String attributedStringValue = CFAttributedStringGetString(attributedString); CFIndex length = attributedStringValue.length(); if (!length) return; CFRange effectiveRange = CFRangeMake(0, 0); while ((effectiveRange.location + effectiveRange.length) < length) { CFDictionaryRef attributes = CFAttributedStringGetAttributes(attributedString, effectiveRange.location + effectiveRange.length, &effectiveRange); if (!attributes) continue; StringBuilder tagStart; CFStringRef valueString; String tagEnd; CFIndex attributeCount = CFDictionaryGetCount(attributes); Vector<const void*> keys(attributeCount); Vector<const void*> values(attributeCount); CFDictionaryGetKeysAndValues(attributes, keys.data(), values.data()); for (CFIndex i = 0; i < attributeCount; ++i) { CFStringRef key = static_cast<CFStringRef>(keys[i]); CFTypeRef value = values[i]; if (CFGetTypeID(key) != CFStringGetTypeID() || !CFStringGetLength(key)) continue; if (CFStringCompare(key, kCMTextMarkupAttribute_Alignment, 0) == kCFCompareEqualTo) { valueString = static_cast<CFStringRef>(value); if (CFGetTypeID(valueString) != CFStringGetTypeID() || !CFStringGetLength(valueString)) continue; if (processed & Align) continue; processed |= Align; if (CFStringCompare(valueString, kCMTextMarkupAlignmentType_Start, 0) == kCFCompareEqualTo) cueData->setAlign(GenericCueData::Start); else if (CFStringCompare(valueString, kCMTextMarkupAlignmentType_Middle, 0) == kCFCompareEqualTo) cueData->setAlign(GenericCueData::Middle); else if (CFStringCompare(valueString, kCMTextMarkupAlignmentType_End, 0) == kCFCompareEqualTo) cueData->setAlign(GenericCueData::End); else ASSERT_NOT_REACHED(); continue; } if (CFStringCompare(key, kCMTextMarkupAttribute_BoldStyle, 0) == kCFCompareEqualTo) { if (static_cast<CFBooleanRef>(value) != kCFBooleanTrue) continue; tagStart.append("<b>"); tagEnd.insert("</b>", 0); continue; } if (CFStringCompare(key, kCMTextMarkupAttribute_ItalicStyle, 0) == kCFCompareEqualTo) { if (static_cast<CFBooleanRef>(value) != kCFBooleanTrue) continue; tagStart.append("<i>"); tagEnd.insert("</i>", 0); continue; } if (CFStringCompare(key, kCMTextMarkupAttribute_UnderlineStyle, 0) == kCFCompareEqualTo) { if (static_cast<CFBooleanRef>(value) != kCFBooleanTrue) continue; tagStart.append("<u>"); tagEnd.insert("</u>", 0); continue; } if (CFStringCompare(key, kCMTextMarkupAttribute_OrthogonalLinePositionPercentageRelativeToWritingDirection, 0) == kCFCompareEqualTo) { if (CFGetTypeID(value) != CFNumberGetTypeID()) continue; if (processed & Line) continue; processed |= Line; CFNumberRef valueNumber = static_cast<CFNumberRef>(value); double line; CFNumberGetValue(valueNumber, kCFNumberFloat64Type, &line); cueData->setLine(line); continue; } if (CFStringCompare(key, kCMTextMarkupAttribute_TextPositionPercentageRelativeToWritingDirection, 0) == kCFCompareEqualTo) { if (CFGetTypeID(value) != CFNumberGetTypeID()) continue; if (processed & Position) continue; processed |= Position; CFNumberRef valueNumber = static_cast<CFNumberRef>(value); double position; CFNumberGetValue(valueNumber, kCFNumberFloat64Type, &position); cueData->setPosition(position); continue; } if (CFStringCompare(key, kCMTextMarkupAttribute_WritingDirectionSizePercentage, 0) == kCFCompareEqualTo) { if (CFGetTypeID(value) != CFNumberGetTypeID()) continue; if (processed & Size) continue; processed |= Size; CFNumberRef valueNumber = static_cast<CFNumberRef>(value); double size; CFNumberGetValue(valueNumber, kCFNumberFloat64Type, &size); cueData->setSize(size); continue; } if (CFStringCompare(key, kCMTextMarkupAttribute_VerticalLayout, 0) == kCFCompareEqualTo) { valueString = static_cast<CFStringRef>(value); if (CFGetTypeID(valueString) != CFStringGetTypeID() || !CFStringGetLength(valueString)) continue; if (CFStringCompare(valueString, kCMTextVerticalLayout_LeftToRight, 0) == kCFCompareEqualTo) tagStart.append(leftToRightMark); else if (CFStringCompare(valueString, kCMTextVerticalLayout_RightToLeft, 0) == kCFCompareEqualTo) tagStart.append(rightToLeftMark); continue; } if (CFStringCompare(key, kCMTextMarkupAttribute_BaseFontSizePercentageRelativeToVideoHeight, 0) == kCFCompareEqualTo) { if (CFGetTypeID(value) != CFNumberGetTypeID()) continue; CFNumberRef valueNumber = static_cast<CFNumberRef>(value); double baseFontSize; CFNumberGetValue(valueNumber, kCFNumberFloat64Type, &baseFontSize); cueData->setBaseFontSize(baseFontSize); continue; } if (CFStringCompare(key, kCMTextMarkupAttribute_RelativeFontSize, 0) == kCFCompareEqualTo) { if (CFGetTypeID(value) != CFNumberGetTypeID()) continue; CFNumberRef valueNumber = static_cast<CFNumberRef>(value); double relativeFontSize; CFNumberGetValue(valueNumber, kCFNumberFloat64Type, &relativeFontSize); cueData->setRelativeFontSize(relativeFontSize); continue; } if (CFStringCompare(key, kCMTextMarkupAttribute_FontFamilyName, 0) == kCFCompareEqualTo) { valueString = static_cast<CFStringRef>(value); if (CFGetTypeID(valueString) != CFStringGetTypeID() || !CFStringGetLength(valueString)) continue; if (processed & FontName) continue; processed |= FontName; cueData->setFontName(valueString); continue; } if (CFStringCompare(key, kCMTextMarkupAttribute_ForegroundColorARGB, 0) == kCFCompareEqualTo) { CFArrayRef arrayValue = static_cast<CFArrayRef>(value); if (CFGetTypeID(arrayValue) != CFArrayGetTypeID()) continue; RGBA32 color; if (!makeRGBA32FromARGBCFArray(arrayValue, color)) continue; cueData->setForegroundColor(color); } if (CFStringCompare(key, kCMTextMarkupAttribute_BackgroundColorARGB, 0) == kCFCompareEqualTo) { CFArrayRef arrayValue = static_cast<CFArrayRef>(value); if (CFGetTypeID(arrayValue) != CFArrayGetTypeID()) continue; RGBA32 color; if (!makeRGBA32FromARGBCFArray(arrayValue, color)) continue; cueData->setBackgroundColor(color); } if (CFStringCompare(key, kCMTextMarkupAttribute_CharacterBackgroundColorARGB, 0) == kCFCompareEqualTo) { CFArrayRef arrayValue = static_cast<CFArrayRef>(value); if (CFGetTypeID(arrayValue) != CFArrayGetTypeID()) continue; RGBA32 color; if (!makeRGBA32FromARGBCFArray(arrayValue, color)) continue; cueData->setHighlightColor(color); } } content.append(tagStart); content.append(attributedStringValue.substring(effectiveRange.location, effectiveRange.length)); content.append(tagEnd); } if (content.length()) cueData->setContent(content.toString()); }