void createLayout (TextLayout& layout, const AttributedString& text, IDWriteFactory* const directWriteFactory,
                       ID2D1Factory* const direct2dFactory, IDWriteFontCollection* const fontCollection)
    {
        // To add color to text, we need to create a D2D render target
        // Since we are not actually rendering to a D2D context we create a temporary GDI render target

        D2D1_RENDER_TARGET_PROPERTIES d2dRTProp = D2D1::RenderTargetProperties (D2D1_RENDER_TARGET_TYPE_SOFTWARE,
                                                                                D2D1::PixelFormat (DXGI_FORMAT_B8G8R8A8_UNORM,
                                                                                                   D2D1_ALPHA_MODE_IGNORE),
                                                                                0, 0,
                                                                                D2D1_RENDER_TARGET_USAGE_GDI_COMPATIBLE,
                                                                                D2D1_FEATURE_LEVEL_DEFAULT);
        ComSmartPtr<ID2D1DCRenderTarget> renderTarget;
        HRESULT hr = direct2dFactory->CreateDCRenderTarget (&d2dRTProp, renderTarget.resetAndGetPointerAddress());

        Font defaultFont;
        BOOL fontFound = false;
        uint32 fontIndex;
        fontCollection->FindFamilyName (defaultFont.getTypefaceName().toWideCharPointer(), &fontIndex, &fontFound);

        if (! fontFound)
            fontIndex = 0;

        ComSmartPtr<IDWriteFontFamily> dwFontFamily;
        hr = fontCollection->GetFontFamily (fontIndex, dwFontFamily.resetAndGetPointerAddress());

        ComSmartPtr<IDWriteFont> dwFont;
        hr = dwFontFamily->GetFirstMatchingFont (DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STRETCH_NORMAL, DWRITE_FONT_STYLE_NORMAL,
                                                 dwFont.resetAndGetPointerAddress());

        const float defaultFontHeightToEmSizeFactor = getFontHeightToEmSizeFactor (dwFont);

        jassert (directWriteFactory != nullptr);

        ComSmartPtr<IDWriteTextFormat> dwTextFormat;
        hr = directWriteFactory->CreateTextFormat (defaultFont.getTypefaceName().toWideCharPointer(), fontCollection,
                                                   DWRITE_FONT_WEIGHT_REGULAR, DWRITE_FONT_STYLE_NORMAL, DWRITE_FONT_STRETCH_NORMAL,
                                                   defaultFont.getHeight() * defaultFontHeightToEmSizeFactor,
                                                   L"en-us", dwTextFormat.resetAndGetPointerAddress());

        setTextFormatProperties (text, dwTextFormat);

        const int textLen = text.getText().length();

        ComSmartPtr<IDWriteTextLayout> dwTextLayout;
        hr = directWriteFactory->CreateTextLayout (text.getText().toWideCharPointer(), textLen,
                                                   dwTextFormat, layout.getWidth(),
                                                   1.0e7f, dwTextLayout.resetAndGetPointerAddress());

        const int numAttributes = text.getNumAttributes();

        for (int i = 0; i < numAttributes; ++i)
            addAttributedRange (*text.getAttribute (i), dwTextLayout, textLen, renderTarget, fontCollection);

        UINT32 actualLineCount = 0;
        hr = dwTextLayout->GetLineMetrics (nullptr, 0, &actualLineCount);

        layout.ensureStorageAllocated (actualLineCount);

        {
            ComSmartPtr<CustomDirectWriteTextRenderer> textRenderer (new CustomDirectWriteTextRenderer (fontCollection));
            hr = dwTextLayout->Draw (&layout, textRenderer, 0, 0);
        }

        HeapBlock <DWRITE_LINE_METRICS> dwLineMetrics (actualLineCount);
        hr = dwTextLayout->GetLineMetrics (dwLineMetrics, actualLineCount, &actualLineCount);
        int lastLocation = 0;
        const int numLines = jmin ((int) actualLineCount, layout.getNumLines());

        for (int i = 0; i < numLines; ++i)
        {
            lastLocation = dwLineMetrics[i].length;
            layout.getLine(i).stringRange = Range<int> (lastLocation, (int) lastLocation + dwLineMetrics[i].length);
        }
    }
Esempio n. 2
0
StringArray Font::findAllTypefaceStyles(const String& family)
{
    StringArray results;

    #if JUCE_USE_DIRECTWRITE
    const Direct2DFactories& factories = Direct2DFactories::getInstance();

    if (factories.systemFonts != nullptr)
    {
        BOOL fontFound = false;
        uint32 fontIndex = 0;
        HRESULT hr = factories.systemFonts->FindFamilyName (family.toWideCharPointer(), &fontIndex, &fontFound);
        if (! fontFound)
            fontIndex = 0;

        // Get the font family using the search results
        // Fonts like: Times New Roman, Times New Roman Bold, Times New Roman Italic are all in the same font family
        ComSmartPtr<IDWriteFontFamily> dwFontFamily;
        hr = factories.systemFonts->GetFontFamily (fontIndex, dwFontFamily.resetAndGetPointerAddress());

        // Get the font faces
        ComSmartPtr<IDWriteFont> dwFont;
        uint32 fontFacesCount = 0;
        fontFacesCount = dwFontFamily->GetFontCount();

        for (uint32 i = 0; i < fontFacesCount; ++i)
        {
                hr = dwFontFamily->GetFont (i, dwFont.resetAndGetPointerAddress());

                ComSmartPtr<IDWriteLocalizedStrings> dwFaceNames;
                hr = dwFont->GetFaceNames (dwFaceNames.resetAndGetPointerAddress());
                jassert (dwFaceNames != nullptr);

                uint32 index = 0;
                BOOL exists = false;
                hr = dwFaceNames->FindLocaleName (L"en-us", &index, &exists);
                if (! exists)
                    index = 0;

                uint32 length = 0;
                hr = dwFaceNames->GetStringLength (index, &length);

                HeapBlock <wchar_t> styleName (length + 1);
                hr = dwFaceNames->GetString (index, styleName, length + 1);

                String style (styleName);

                // For unknown reasons, DirectWrite does not enumerate the Arial Narrow fonts properly.
                // It uses the same style name "Narrow" for all four fonts. Since only one of these fonts
                // is accessible, we will ignore the duplicates.
                if (style == "Narrow" && results.contains("Narrow")) continue;
                // DirectWrite automatically adds extra bold and oblique font styles which are algorithmic
                // style simulations. These styles don't show up in any other software. We will ignore them.
                if (dwFont->GetSimulations() != DWRITE_FONT_SIMULATIONS_NONE) continue;

                results.add(style);
        }
    }
    else
    #endif
    {
        results.add ("Regular");
        results.add ("Italic");
        results.add ("Bold");
        results.add ("Bold Italic");
    }

    return results;
}
    bool setupLayout (const AttributedString& text, const float maxWidth, const float maxHeight,
                      ID2D1RenderTarget& renderTarget, IDWriteFactory& directWriteFactory,
                      IDWriteFontCollection& fontCollection, ComSmartPtr<IDWriteTextLayout>& textLayout)
    {
        // To add color to text, we need to create a D2D render target
        // Since we are not actually rendering to a D2D context we create a temporary GDI render target

        Font defaultFont;
        BOOL fontFound = false;
        uint32 fontIndex;
        fontCollection.FindFamilyName (defaultFont.getTypeface()->getName().toWideCharPointer(), &fontIndex, &fontFound);

        if (! fontFound)
            fontIndex = 0;

        ComSmartPtr<IDWriteFontFamily> dwFontFamily;
        HRESULT hr = fontCollection.GetFontFamily (fontIndex, dwFontFamily.resetAndGetPointerAddress());

        ComSmartPtr<IDWriteFont> dwFont;
        hr = dwFontFamily->GetFirstMatchingFont (DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STRETCH_NORMAL, DWRITE_FONT_STYLE_NORMAL,
                                                 dwFont.resetAndGetPointerAddress());
        jassert (dwFont != nullptr);

        const float defaultFontHeightToEmSizeFactor = getFontHeightToEmSizeFactor (*dwFont);

        ComSmartPtr<IDWriteTextFormat> dwTextFormat;
        hr = directWriteFactory.CreateTextFormat (defaultFont.getTypefaceName().toWideCharPointer(), &fontCollection,
                                                  DWRITE_FONT_WEIGHT_REGULAR, DWRITE_FONT_STYLE_NORMAL, DWRITE_FONT_STRETCH_NORMAL,
                                                  defaultFont.getHeight() * defaultFontHeightToEmSizeFactor,
                                                  L"en-us", dwTextFormat.resetAndGetPointerAddress());

        setTextFormatProperties (text, *dwTextFormat);

        {
            DWRITE_TRIMMING trimming = { DWRITE_TRIMMING_GRANULARITY_CHARACTER, 0, 0 };
            ComSmartPtr<IDWriteInlineObject> trimmingSign;
            hr = directWriteFactory.CreateEllipsisTrimmingSign (dwTextFormat, trimmingSign.resetAndGetPointerAddress());
            hr = dwTextFormat->SetTrimming (&trimming, trimmingSign);
        }

        const int textLen = text.getText().length();

        hr = directWriteFactory.CreateTextLayout (text.getText().toWideCharPointer(), textLen, dwTextFormat,
                                                  maxWidth, maxHeight, textLayout.resetAndGetPointerAddress());

        if (FAILED (hr) || textLayout == nullptr)
            return false;

        const int numAttributes = text.getNumAttributes();

        for (int i = 0; i < numAttributes; ++i)
            addAttributedRange (*text.getAttribute (i), *textLayout, textLen, renderTarget, fontCollection);

        return true;
    }
    bool createFileCaptureFilter (const File& file, int quality)
    {
        removeFileCaptureFilter();
        file.deleteFile();
        mediaControl->Stop();
        firstRecordedTime = Time();
        recordNextFrameTime = true;
        previewMaxFPS = 60;

        HRESULT hr = asfWriter.CoCreateInstance (CLSID_WMAsfWriter);

        if (SUCCEEDED (hr))
        {
            ComSmartPtr<IFileSinkFilter> fileSink;
            hr = asfWriter.QueryInterface (fileSink);

            if (SUCCEEDED (hr))
            {
                hr = fileSink->SetFileName (file.getFullPathName().toWideCharPointer(), 0);

                if (SUCCEEDED (hr))
                {
                    hr = graphBuilder->AddFilter (asfWriter, _T("AsfWriter"));

                    if (SUCCEEDED (hr))
                    {
                        ComSmartPtr<IConfigAsfWriter> asfConfig;
                        hr = asfWriter.QueryInterface (asfConfig);
                        asfConfig->SetIndexMode (true);
                        ComSmartPtr<IWMProfileManager> profileManager;
                        hr = WMCreateProfileManager (profileManager.resetAndGetPointerAddress());

                        // This gibberish is the DirectShow profile for a video-only wmv file.
                        String prof ("<profile version=\"589824\" storageformat=\"1\" name=\"Quality\" description=\"Quality type for output.\">"
                                       "<streamconfig majortype=\"{73646976-0000-0010-8000-00AA00389B71}\" streamnumber=\"1\" "
                                                     "streamname=\"Video Stream\" inputname=\"Video409\" bitrate=\"894960\" "
                                                     "bufferwindow=\"0\" reliabletransport=\"1\" decodercomplexity=\"AU\" rfc1766langid=\"en-us\">"
                                         "<videomediaprops maxkeyframespacing=\"50000000\" quality=\"90\"/>"
                                         "<wmmediatype subtype=\"{33564D57-0000-0010-8000-00AA00389B71}\" bfixedsizesamples=\"0\" "
                                                      "btemporalcompression=\"1\" lsamplesize=\"0\">"
                                         "<videoinfoheader dwbitrate=\"894960\" dwbiterrorrate=\"0\" avgtimeperframe=\"$AVGTIMEPERFRAME\">"
                                             "<rcsource left=\"0\" top=\"0\" right=\"$WIDTH\" bottom=\"$HEIGHT\"/>"
                                             "<rctarget left=\"0\" top=\"0\" right=\"$WIDTH\" bottom=\"$HEIGHT\"/>"
                                             "<bitmapinfoheader biwidth=\"$WIDTH\" biheight=\"$HEIGHT\" biplanes=\"1\" bibitcount=\"24\" "
                                                               "bicompression=\"WMV3\" bisizeimage=\"0\" bixpelspermeter=\"0\" biypelspermeter=\"0\" "
                                                               "biclrused=\"0\" biclrimportant=\"0\"/>"
                                           "</videoinfoheader>"
                                         "</wmmediatype>"
                                       "</streamconfig>"
                                     "</profile>");

                        const int fps[] = { 10, 15, 30 };
                        int maxFramesPerSecond = fps [jlimit (0, numElementsInArray (fps) - 1, quality & 0xff)];

                        if ((quality & 0xff000000) != 0) // (internal hacky way to pass explicit frame rates for testing)
                            maxFramesPerSecond = (quality >> 24) & 0xff;

                        prof = prof.replace ("$WIDTH", String (width))
                                   .replace ("$HEIGHT", String (height))
                                   .replace ("$AVGTIMEPERFRAME", String (10000000 / maxFramesPerSecond));

                        ComSmartPtr<IWMProfile> currentProfile;
                        hr = profileManager->LoadProfileByData (prof.toWideCharPointer(), currentProfile.resetAndGetPointerAddress());
                        hr = asfConfig->ConfigureFilterUsingProfile (currentProfile);

                        if (SUCCEEDED (hr))
                        {
                            ComSmartPtr<IPin> asfWriterInputPin;

                            if (getPin (asfWriter, PINDIR_INPUT, asfWriterInputPin, "Video Input 01"))
                            {
                                hr = graphBuilder->Connect (smartTeeCaptureOutputPin, asfWriterInputPin);

                                if (SUCCEEDED (hr) && openedSuccessfully && activeUsers > 0
                                     && SUCCEEDED (mediaControl->Run()))
                                {
                                    previewMaxFPS = (quality < 2) ? 15 : 25; // throttle back the preview comps to try to leave the cpu free for encoding

                                    if ((quality & 0x00ff0000) != 0)  // (internal hacky way to pass explicit frame rates for testing)
                                        previewMaxFPS = (quality >> 16) & 0xff;

                                    return true;
                                }
                            }
                        }
                    }
                }
            }
    DShowCameraDeviceInteral (CameraDevice* const owner_,
                              const ComSmartPtr <ICaptureGraphBuilder2>& captureGraphBuilder_,
                              const ComSmartPtr <IBaseFilter>& filter_,
                              int minWidth, int minHeight,
                              int maxWidth, int maxHeight)
      : owner (owner_),
        captureGraphBuilder (captureGraphBuilder_),
        filter (filter_),
        ok (false),
        imageNeedsFlipping (false),
        width (0),
        height (0),
        activeUsers (0),
        recordNextFrameTime (false),
        previewMaxFPS (60)
    {
        HRESULT hr = graphBuilder.CoCreateInstance (CLSID_FilterGraph);
        if (FAILED (hr))
            return;

        hr = captureGraphBuilder->SetFiltergraph (graphBuilder);
        if (FAILED (hr))
            return;

        hr = graphBuilder.QueryInterface (mediaControl);
        if (FAILED (hr))
            return;

        {
            ComSmartPtr <IAMStreamConfig> streamConfig;

            hr = captureGraphBuilder->FindInterface (&PIN_CATEGORY_CAPTURE, 0, filter,
                                                     IID_IAMStreamConfig, (void**) streamConfig.resetAndGetPointerAddress());

            if (streamConfig != nullptr)
            {
                getVideoSizes (streamConfig);

                if (! selectVideoSize (streamConfig, minWidth, minHeight, maxWidth, maxHeight))
                    return;
            }
        }

        hr = graphBuilder->AddFilter (filter, _T("Video Capture"));
        if (FAILED (hr))
            return;

        hr = smartTee.CoCreateInstance (CLSID_SmartTee);
        if (FAILED (hr))
            return;

        hr = graphBuilder->AddFilter (smartTee, _T("Smart Tee"));
        if (FAILED (hr))
            return;

        if (! connectFilters (filter, smartTee))
            return;

        ComSmartPtr <IBaseFilter> sampleGrabberBase;
        hr = sampleGrabberBase.CoCreateInstance (CLSID_SampleGrabber);
        if (FAILED (hr))
            return;

        hr = sampleGrabberBase.QueryInterface (IID_ISampleGrabber, sampleGrabber);
        if (FAILED (hr))
            return;

        {
            AM_MEDIA_TYPE mt = { 0 };
            mt.majortype = MEDIATYPE_Video;
            mt.subtype = MEDIASUBTYPE_RGB24;
            mt.formattype = FORMAT_VideoInfo;
            sampleGrabber->SetMediaType (&mt);
        }

        callback = new GrabberCallback (*this);
        hr = sampleGrabber->SetCallback (callback, 1);

        hr = graphBuilder->AddFilter (sampleGrabberBase, _T("Sample Grabber"));
        if (FAILED (hr))
            return;

        ComSmartPtr <IPin> grabberInputPin;
        if (! (getPin (smartTee, PINDIR_OUTPUT, smartTeeCaptureOutputPin, "capture")
                && getPin (smartTee, PINDIR_OUTPUT, smartTeePreviewOutputPin, "preview")
                && getPin (sampleGrabberBase, PINDIR_INPUT, grabberInputPin)))
            return;

        hr = graphBuilder->Connect (smartTeePreviewOutputPin, grabberInputPin);
        if (FAILED (hr))
            return;

        AM_MEDIA_TYPE mt = { 0 };
        hr = sampleGrabber->GetConnectedMediaType (&mt);
        VIDEOINFOHEADER* pVih = (VIDEOINFOHEADER*) (mt.pbFormat);
        width = pVih->bmiHeader.biWidth;
        height = pVih->bmiHeader.biHeight;

        ComSmartPtr <IBaseFilter> nullFilter;
        hr = nullFilter.CoCreateInstance (CLSID_NullRenderer);
        hr = graphBuilder->AddFilter (nullFilter, _T("Null Renderer"));

        if (connectFilters (sampleGrabberBase, nullFilter)
              && addGraphToRot())
        {
            activeImage = Image (Image::RGB, width, height, true);
            loadingImage = Image (Image::RGB, width, height, true);

            ok = true;
        }
    }
    bool tryInitialisingWithFormat (const bool useFloat, const int bytesPerSampleToTry)
    {
        WAVEFORMATEXTENSIBLE format;
        zerostruct (format);

        if (numChannels <= 2 && bytesPerSampleToTry <= 2)
        {
            format.Format.wFormatTag = WAVE_FORMAT_PCM;
        }
        else
        {
            format.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
            format.Format.cbSize = sizeof (WAVEFORMATEXTENSIBLE) - sizeof (WAVEFORMATEX);
        }

        format.Format.nSamplesPerSec = roundDoubleToInt (sampleRate);
        format.Format.nChannels = (WORD) numChannels;
        format.Format.wBitsPerSample = (WORD) (8 * bytesPerSampleToTry);
        format.Format.nAvgBytesPerSec = (DWORD) (format.Format.nSamplesPerSec * numChannels * bytesPerSampleToTry);
        format.Format.nBlockAlign = (WORD) (numChannels * bytesPerSampleToTry);
        format.SubFormat = useFloat ? KSDATAFORMAT_SUBTYPE_IEEE_FLOAT : KSDATAFORMAT_SUBTYPE_PCM;
        format.Samples.wValidBitsPerSample = format.Format.wBitsPerSample;

        switch (numChannels)
        {
            case 1:     format.dwChannelMask = SPEAKER_FRONT_CENTER; break;
            case 2:     format.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT; break;
            case 4:     format.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT; break;
            case 6:     format.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_LOW_FREQUENCY | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT; break;
            case 8:     format.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_LOW_FREQUENCY | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT | SPEAKER_FRONT_LEFT_OF_CENTER | SPEAKER_FRONT_RIGHT_OF_CENTER; break;
            default:    break;
        }

        WAVEFORMATEXTENSIBLE* nearestFormat = 0;

        HRESULT hr = client->IsFormatSupported (AUDCLNT_SHAREMODE_SHARED, (WAVEFORMATEX*) &format, (WAVEFORMATEX**) &nearestFormat);
        logFailure (hr);

        if (hr == S_FALSE && format.Format.nSamplesPerSec == nearestFormat->Format.nSamplesPerSec)
        {
            wasapi_copyWavFormat (format, (WAVEFORMATEX*) nearestFormat);
            hr = S_OK;
        }

        CoTaskMemFree (nearestFormat);

        GUID session;
        if (hr == S_OK
             && OK (client->Initialize (AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_EVENTCALLBACK,
                                        0, 0, (WAVEFORMATEX*) &format, &session)))
        {
            actualNumChannels = format.Format.nChannels;
            const bool isFloat = format.Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE && format.SubFormat == KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
            bytesPerSample = format.Format.wBitsPerSample / 8;
            dataFormat = isFloat ? AudioDataConverters::float32LE
                                 : (bytesPerSample == 4 ? AudioDataConverters::int32LE
                                                        : ((bytesPerSample == 3 ? AudioDataConverters::int24LE
                                                                                : AudioDataConverters::int16LE)));
            return true;
        }

        return false;
    }
    bool isRendererConnected()
    {
        ComSmartPtr <IEnumPins> enumPins;

        HRESULT hr = baseFilter->EnumPins (enumPins.resetAndGetPointerAddress());

        if (SUCCEEDED (hr))
            hr = enumPins->Reset();

        ComSmartPtr<IPin> pin;

        while (SUCCEEDED (hr)
                && enumPins->Next (1, pin.resetAndGetPointerAddress(), nullptr) == S_OK)
        {
            ComSmartPtr<IPin> otherPin;

            hr = pin->ConnectedTo (otherPin.resetAndGetPointerAddress());

            if (SUCCEEDED (hr))
            {
                PIN_DIRECTION direction;
                hr = pin->QueryDirection (&direction);

                if (SUCCEEDED (hr) && direction == PINDIR_INPUT)
                    return true;
            }
            else if (hr == VFW_E_NOT_CONNECTED)
            {
                hr = S_OK;
            }
        }

        return false;
    }
 bool checkDShowAvailability()
 {
     ComSmartPtr <IGraphBuilder> graph;
     return SUCCEEDED (graph.CoCreateInstance (CLSID_FilterGraph));
 }