O Alcinoe é uma biblioteca de componentes de código aberto para Delphi e C++Builder, mantida no GitHub pela Zeus64. Ela cobre um terreno que a RTL do VCL e do FireMonkey deixa a cargo de terceiros: um reprodutor de vídeo acelerado por GPU, um wrapper de WebRTC, controles de edição nativos de iOS e Android, um analisador JSON/BSON de modo duplo, um cliente MongoDB com pool de conexões, um wrapper de ImageMagick e uma coleção de controles FireMonkey que contornam por completo o pipeline de renderização padrão. A biblioteca construiu sua reputação no Rio (10.3.3) e no Sydney (10.4.2) e, desde então, acompanhou cada versão da Embarcadero. No momento em que este texto é escrito, ela é totalmente compatível com o Delphi 11.1 Alexandria e o Delphi Athens 12.3
Colocando o Alcinoe em um projeto
A instalação se divide em uma pergunta: você precisa de suporte em tempo de projeto para os controles visuais do Alcinoe? Se não, dispense a BPL por completo. Adicione {alcinoe_rootdir}\source ao caminho de busca de bibliotecas do projeto e pronto. Todo componente não visual, incluindo os analisadores, os clientes de banco de dados e os utilitários de string, compila a partir do código-fonte sem registrar nada
Quando você de fato precisa de suporte em tempo de projeto, o caminho é um pouco mais longo. Abra Component > Install Packages na IDE do Delphi, navegue até a BPL correspondente à sua versão (por exemplo {alcinoe_rootdir}\lib\bpl\alcinoe\Win32\alexandria\Alcinoe_alexandria.bpl), instale-a e, ainda assim, adicione {alcinoe_rootdir}\source ao caminho de busca. A BPL registra os componentes; o diretório de código-fonte é o que o compilador encontra ao compilar o seu projeto
O Alcinoe traz patches opcionais para os fontes da RTL da Embarcadero. Se você os quiser, navegue até {alcinoe_rootdir}\embarcadero\, escolha o subdiretório da sua versão e execute update.bat. O script espera o GIT no PATH e presume um local de instalação padrão da Embarcadero. Ele busca o código-fonte original da RTL e aplica os patches. Concluído isso, adicione esse diretório de fontes com patch ao caminho de busca do projeto para que o compilador o encontre antes da cópia somente leitura na árvore de instalação da Embarcadero. Nada disso é obrigatório para começar; isso só importa se você esbarrar em bugs que os patches resolvem
Android e o proxy de desugaring do D8
Vários componentes do Alcinoe (WebRTC, vídeo baseado em ExoPlayer) dependem de bibliotecas Java que usam recursos de linguagem do Java 8. A cadeia de ferramentas Android que acompanha versões mais antigas do Delphi usa dx.bat para a conversão DEX, que não consegue lidar com esses bytecodes em níveis de API abaixo de 26. A solução é o desugaring, que o D8 trata automaticamente quando invocado diretamente. O Alcinoe fornece um script proxy em {alcinoe_rootdir}\tools\D8Proxy\dx.bat que encaminha as chamadas do sistema de build do Delphi para o D8, tornando o desugaring transparente. Substitua o dx.bat original no diretório build-tools do seu Android SDK (normalmente C:\SDKs\android\build-tools\30.0.3\) por esse proxy. A Embarcadero acompanhou o problema subjacente no RSP-24155; versões posteriores das ferramentas do SDK o resolveram diretamente, então verifique se a sua cadeia de ferramentas atual ainda precisa da solução alternativa
O problema de renderização do FireMonkey e a resposta do Alcinoe
O ciclo de pintura padrão do FireMonkey se torna um gargalo em interfaces com muita rolagem. Um único TRectangle com cantos arredondados pode levar cerca de 3 ms para repintar, porque a implementação padrão recalcula o caminho a cada quadro. Com 20 desses controles visíveis, isso soma 60 ms por passagem de quadro, o que limita a taxa de quadros efetiva bem abaixo do limiar para uma rolagem fluida
O Alcinoe resolve isso com um buffer residente em GPU por controle. A primeira pintura renderiza o controle em uma TTexture armazenada na memória da GPU. As repinturas subsequentes fazem um blit dessa textura em vez de reexecutar o algoritmo de pintura. O resultado medido no mesmo retângulo arredondado cai de cerca de 3 ms para cerca de 0,1 ms. Além do buffer, o Alcinoe substitui o desenho de caminhos via OpenGL para formas básicas por APIs de desenho nativas do Android e do iOS, contornando o compromisso entre qualidade e desempenho ligado a Form.Quality. Os controles relevantes são TALRectangle, TALCircle e um conjunto de contêineres de layout aprimorados, incluindo um ScrollBox e um TabControl
TALJsonDocument: DOM e SAX em um único tipo
TALJsonDocument é o analisador JSON e BSON do Alcinoe. Ele suporta dois modos de travessia. O modo DOM constrói uma árvore de objetos em memória, dando acesso aleatório a qualquer nó ao custo de memória proporcional ao tamanho do documento. O modo SAX dispara eventos à medida que o analisador lê cada token, sem reter nenhuma árvore, o que é a escolha certa quando você precisa filtrar um documento grande e manter apenas alguns poucos valores. Os analisadores DOM em Delphi (DBXJSON, SuperObject e os demais) costumam ser de três a cinco vezes mais lentos do que uma abordagem SAX para o mesmo conteúdo, porque cada alocação de nó carrega a sobrecarga de criação de objeto além do próprio trabalho de análise
O tipo segue o mesmo padrão de navegação por nós do TALXMLDocument. Uma leitura DOM mínima se parece com isto:
MyJsonDoc.LoadFromJSON(AJsonStr, False {modo dom});
MyJsonDoc.ParseOptions := [poAllowComments];
// ler valores escalares
ShowMessage(MyJsonDoc.ChildNodes['name'].ChildNodes['first'].Text);
ShowMessage(IntToStr(MyJsonDoc.ChildNodes['_id'].Int32));
// iterar um array
for I := 0 to MyJsonDoc.ChildNodes['contribs'].ChildNodes.Count - 1 do
Writeln(MyJsonDoc.ChildNodes['contribs'].ChildNodes[I].Text);
Para o modo SAX, atribua um procedimento anônimo a OnParseText antes de chamar LoadFromJSON com o segundo argumento definido como True. O callback recebe o caminho do nó, o nome, o valor e um TALJSONNodeSubType que identifica o tipo JSON (string, inteiro, ponto flutuante, booleano e assim por diante). Esse modo não produz nenhuma alocação de heap para os nós, então ele escala para documentos arbitrariamente grandes sem estourar o orçamento de memória
O TALJsonDocument também lê e grava BSON de forma nativa; passe True como flag de BSON para LoadFromFile ou SaveToFile. Uma segunda variante, TALJsonDocumentU, usa UnicodeString (UTF-16) internamente em vez de AnsiString (UTF-8) para contextos em que o código ao redor trabalha inteiramente em Unicode
Cliente MongoDB e pool de conexões
O driver MongoDB do Alcinoe cobre as operações de consulta comuns e lida nativamente com o pool de conexões. O cliente simples, TAlMongoDBClient, abre e fecha uma única conexão por operação. A variante com pool, TAlMongoDBConnectionPoolClient, mantém um conjunto de conexões ativas e entrega uma a cada thread chamadora a partir do pool, devolvendo-a quando a chamada termina. Esse modelo impede que múltiplas threads bloqueiem umas às outras na configuração da conexão, o que importa sempre que workers em segundo plano estão consultando o mesmo banco de dados simultaneamente. Para cursores tailable em coleções capped, o TALMongoDBTailMonitoringThread observa novos documentos e dispara um callback quando eles chegam, que é o padrão usual para streaming de logs ou notificação de mudanças sem polling
Outros componentes que vale conhecer
O ALVideoPlayer renderiza o vídeo em uma TTexture em vez de uma janela de overlay, de modo que outros controles FireMonkey podem ficar acima dele na ordem Z. O backend Android usa o ExoPlayer, que adiciona suporte a DASH, HLS e SmoothStreaming além do que o MediaPlayer nativo do Android trata. O backend iOS usa AVPlayer com suporte HLS equivalente
O TALWebRTC encapsula a pilha WebRTC para áudio e vídeo peer-to-peer. Ele não requer um navegador nem um plugin, e a conexão atravessa NAT por meio da negociação ICE/STUN/TURN padrão que a biblioteca subjacente cuida
O TALStringList substitui a ordenação baseada em AnsiCompareText do TStringList por uma comparação ordinal independente de locale e um quicksort até 10x mais rápido em listas grandes. A variante com hash, TALHashedStringList, adiciona uma tabela hash interna para busca em O(1) ao custo de uma sobrecarga ligeiramente maior em listas pequenas. Observe que o TALStringList é uma lista AnsiString de 8 bits, não uma Unicode; ela se encaixa bem em código server-side onde o UTF-8 é a codificação de trabalho e a taxa de transferência bruta importa mais do que a comparação sensível a locale
No Windows de 64 bits, a herança FastCode que deu a muitas rotinas de string do Alcinoe sua vantagem de velocidade (majoritariamente assembly x86 escrito à mão) não se transfere. As builds Win64 recorrem às implementações em Pascal, que rodam sensivelmente mais devagar em cargas intensivas de string. O projeto demo\ALStringBenchMark permite medir a diferença no seu hardware antes de se comprometer com uma build de 64 bits onde a taxa de transferência de string seja um gargalo
O código-fonte completo está em github.com/Zeus64/alcinoe