. 인쇄용 정렬

BeginPrint 함수는 인쇄 정렬을 위해 GetLine 함수를 호출하는데 이 함수는 화면상의 정렬함수인 GetLine과는 이름만 같고 인수 목록이 다르므로 완전히 다른 함수이다. 인쇄용의 GetLine 함수 코드는 다음과 같다. 화면용의 GetLine과 논리는 완전히 동일하되 몇 가지 다른 부분이 있다. 다른 부분은 굵게 표시했다.

 

void CApiEdit::GetLine(int Line, int &s, int &e,Ae_PrintInfo *pi)

{

     TCHAR *p;

     int len, acwidth;

     TCHAR *EndPos=NULL;

     TCHAR *EndPosNoSpace=NULL;

     BOOL IsPrevDBCS=FALSE;

    SIZE sz;

 

    pi->Origin=pi->prt.left;

    if (pi->bLineNum) {

        GetTextExtentPoint32(pi->pdc,"999999",6,&sz);

        pi->Origin+=sz.cx;

    }

 

     if (Line == 0) {

          p=buf;

          s=0;

     } else {

          p=buf+pi->pLine[Line-1].End;

          if (*p == 0) {

              s=-1;

              e=-1;

              return;

          }

 

          if (*p == ‘\r’) {

              p+=2;

          }

 

          s=p-buf;

     }

 

    if (pi->nWrap == 0) {

          while (*p != ‘\r’ && *p != 0)

              p++;

     } else {

        for (acwidth=pi->Origin;;) {

              if (*p == ‘\t’) {

                   len=1;

               acwidth =((acwidth-pi->Origin)/pi->TabSize+1)*pi->TabSize+pi->Origin;

                   EndPos=p;

              } else {

                   if (IsDBCS(p-buf)) {

                        len=2;

 

                   if (pi->nWrap==2 || (pi->nWrap==3 && IsPrevDBCS==FALSE)) {

                            EndPos=p;

                            if (*EndPos != ‘ ‘) {

                                 EndPosNoSpace=EndPos;

                            }

                        }

                        IsPrevDBCS=TRUE;

                   } else {

                        len=1;

 

                        if (IsPrevDBCS==TRUE) {

                            EndPos=p;

                            if (*EndPos != ‘ ‘) {

                                 EndPosNoSpace=EndPos;

                            }

                        }

                        IsPrevDBCS=FALSE;

                   }

               GetTextExtentPoint32(pi->pdc,p,len,&sz);

               acwidth+=sz.cx;

              }

 

              if (*p == ‘\r’ || *p == 0) {

                   EndPos=p;

                   break;

              }

 

           if (acwidth > pi->prt.right) {

                   break;

              }

 

              if (*p == ‘ ‘ || *p==‘\t’) {

                   EndPos=p+1;

                   if (*EndPos != ‘ ‘) {

                        EndPosNoSpace=EndPos;

                   }

              }

 

              p+=len;

          }

     }

 

    if (pi->nWrap == 1 || EndPos == NULL) {

          p=p;

     } else {

          p=EndPos;

     }

     if (bNoFirstSpace && *p==‘ ‘ && EndPosNoSpace!=NULL) {

          p=EndPosNoSpace;

     }

     e=p-buf;

}

 

인쇄용 정렬을 하기 때문에 정렬 기준이 되는 몇 가지 값들이 다르다. 자동개행 상태에 대한 정보는 nWrap을 참조하지 않으며 대신 pi->nWrap을 참조한다. pi->nWrap은 인쇄시의 개행 방식을 지정하는 변수이며 설정 대화상자에서 사용자에 의해 선택된다. 만약 인쇄시에도 nWrap 값을 참조한다면 지금 사용자가 문서를 보고 있는 방식대로 인쇄되는데 이는 불합리하다. nWrap 0일 경우 화면은 당장 안보여도 스크롤이 가능하지만 이대로 인쇄하면 용지 바깥으로 문서가 잘려 나간다. 그래서 인쇄시의 정렬 상태는 사용자가 별도로 지정한 pi->nWrap을 따로 참조하도록 하였다.

한 줄이 정렬되는 공간도 다른데 왼쪽 끝은 MarginWidth가 아니라 pi->Origin이라는 값이 대신 사용된다. 이 값은 GetLine 선두에서 용지의 왼쪽 끝에 맞추어진다. 인쇄할 때는 마진이 없고 대신 줄번호 출력 영역이 있는데 만약 줄번호 출력 옵션이 선택되어 있으면 pi->Origin에 십진수 여섯 자리를 출력할 만큼의 공간이 더해진다. 오른쪽 끝은 인쇄 영역의 오른쪽 끝인 pi->prt.right인데 이 좌표는 호스트에 의해 용지의 오른쪽 여백까지로 계산되어 전달된다.

프린터상의 문자 크기는 화면상의 문자 크기보다 훨씬 더 크기 때문에 GetCharWidth 함수로 문자의 폭을 구하지 않았으며 GetTextExtentPoint32 함수로 직접 구해 사용한다. 인쇄용 글꼴은 딱 한 번만 사용되기 때문에 미리 그 크기를 계산해놓을 필요가 없다. 게다가 인쇄라는 동작은 원래부터 느린 동작이라 빠를 필요가 없으며(웬만큼 빨라도 거의 느낄 수 없다.) 실시간으로 문자폭을 구해도 별 상관이 없다.

이런 몇 가지 차이점을 제외하고 인쇄용의 GetLine 함수는 화면용의 GetLine 함수와 크게 다른 점이 없다. 어차피 오른쪽 끝에 닿으면 다음 줄로 넘겨야 하고 단어의 경계에서 자르기, 탭문자는 탭 폭만큼 띄우기 등의 논리는 동일할 수밖에 없다. 잘 하면 두 개의 GetLine 함수를 하나로 합칠 수도 있을 것 같다. 인쇄용인지 화면용인지를 구분하는 인수를 하나 추가하고 이 인수에 따라 다음처럼 코드를 작성하면 된다.

 

if (인쇄용) {

     이렇게 정렬

} else {

     저렇게 정렬

}

 

이런 식으로 합치는 것이 충분히 가능하며 별로 어려운 일도 아니다. 하지만 합치지 않고 별도의 함수를 따로 만든 이유는 화면용 GetLine 함수는 ApiEdit의 전체 속도에 결정적인 영향을 미치는 핵심 함수이기 때문이다. if 조건 판단을 하는 시간조차도 아껴야 할 정도로 최적화에 민감한 함수라 감히 건드리지 않았다. 비슷한 두 함수가 존재함으로써 용량상의 불이익이 있고 코드를 유지하기가 조금 어려워지지만 충분히 감수할만하다.